diff --git a/app/code/Magento/Backend/Block/System/Account/Edit/Form.php b/app/code/Magento/Backend/Block/System/Account/Edit/Form.php
index e620f365e7426..77aaf5e60b47d 100644
--- a/app/code/Magento/Backend/Block/System/Account/Edit/Form.php
+++ b/app/code/Magento/Backend/Block/System/Account/Edit/Form.php
@@ -5,6 +5,9 @@
*/
namespace Magento\Backend\Block\System\Account\Edit;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Locale\OptionInterface;
+
/**
* Adminhtml edit admin user account form
*
@@ -29,6 +32,13 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
*/
protected $_localeLists;
+ /**
+ * Operates with deployed locales.
+ *
+ * @var OptionInterface
+ */
+ private $deployedLocales;
+
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
@@ -37,6 +47,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
* @param \Magento\Backend\Model\Auth\Session $authSession
* @param \Magento\Framework\Locale\ListsInterface $localeLists
* @param array $data
+ * @param OptionInterface $deployedLocales Operates with deployed locales
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
@@ -45,11 +56,14 @@ public function __construct(
\Magento\User\Model\UserFactory $userFactory,
\Magento\Backend\Model\Auth\Session $authSession,
\Magento\Framework\Locale\ListsInterface $localeLists,
- array $data = []
+ array $data = [],
+ OptionInterface $deployedLocales = null
) {
$this->_userFactory = $userFactory;
$this->_authSession = $authSession;
$this->_localeLists = $localeLists;
+ $this->deployedLocales = $deployedLocales
+ ?: ObjectManager::getInstance()->get(OptionInterface::class);
parent::__construct($context, $registry, $formFactory, $data);
}
@@ -121,7 +135,7 @@ protected function _prepareForm()
'name' => 'interface_locale',
'label' => __('Interface Locale'),
'title' => __('Interface Locale'),
- 'values' => $this->_localeLists->getTranslatedOptionLocales(),
+ 'values' => $this->deployedLocales->getTranslatedOptionLocales(),
'class' => 'select'
]
);
diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php
index 58a93e61781ba..8b97ba2bad469 100644
--- a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php
+++ b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php
@@ -122,7 +122,7 @@ public function process($path, $value, $scope, $scopeCode)
$backendModel->beforeSave();
$this->deploymentConfigWriter->saveConfig(
- [ConfigFilePool::APP_CONFIG => $this->arrayManager->set($configPath, [], $backendModel->getValue())],
+ [ConfigFilePool::APP_ENV => $this->arrayManager->set($configPath, [], $backendModel->getValue())],
false
);
diff --git a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php
index 787624b195361..f757115068da2 100644
--- a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php
+++ b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php
@@ -6,6 +6,7 @@
namespace Magento\Config\Console\Command;
use Magento\Config\Console\Command\ConfigSet\ConfigSetProcessorFactory;
+use Magento\Config\Model\Config\PathValidatorFactory;
use Magento\Framework\App\Area;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Scope\ValidatorInterface;
@@ -33,33 +34,49 @@ class ConfigSetCommand extends Command
/**#@-*/
/**
+ * The factory for config:set processors.
+ *
* @var ConfigSetProcessorFactory
*/
private $configSetProcessorFactory;
/**
+ * Scope validator.
+ *
* @var ValidatorInterface
*/
private $validator;
/**
+ * Scope manager.
+ *
* @var ScopeInterface
*/
private $scope;
/**
- * @param ConfigSetProcessorFactory $configSetProcessorFactory
- * @param ValidatorInterface $validator
- * @param ScopeInterface $scope
+ * The factory for path validator.
+ *
+ * @var PathValidatorFactory
+ */
+ private $pathValidatorFactory;
+
+ /**
+ * @param ConfigSetProcessorFactory $configSetProcessorFactory The factory for config:set processors
+ * @param ValidatorInterface $validator Scope validator
+ * @param ScopeInterface $scope Scope manager
+ * @param PathValidatorFactory $pathValidatorFactory The factory for path validator
*/
public function __construct(
ConfigSetProcessorFactory $configSetProcessorFactory,
ValidatorInterface $validator,
- ScopeInterface $scope
+ ScopeInterface $scope,
+ PathValidatorFactory $pathValidatorFactory
) {
$this->configSetProcessorFactory = $configSetProcessorFactory;
$this->validator = $validator;
$this->scope = $scope;
+ $this->pathValidatorFactory = $pathValidatorFactory;
parent::__construct();
}
@@ -118,6 +135,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
// Emulating adminhtml scope to be able to read configs.
$this->scope->setCurrentScope(Area::AREA_ADMINHTML);
+ /**
+ * Validates the entered config path.
+ * Requires emulated area.
+ */
+ $this->pathValidatorFactory->create()->validate(
+ $input->getArgument(ConfigSetCommand::ARG_PATH)
+ );
+
$processor = $input->getOption(static::OPTION_LOCK)
? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK)
: $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT);
diff --git a/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php b/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php
index c60c983c383fa..77d29fa11a1fc 100644
--- a/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php
+++ b/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php
@@ -12,12 +12,18 @@
use Magento\Config\Model\Config\Structure\Element\Field;
use Magento\Framework\Config\ScopeInterface;
use Magento\Framework\App\Area;
+use Magento\Config\Model\Config\Backend\Encrypted;
/**
* Class processes values using backend model which declared in system.xml.
*/
class ValueProcessor
{
+ /**
+ * Placeholder for the output of sensitive data.
+ */
+ const SAFE_PLACEHOLDER = '******';
+
/**
* System configuration structure factory.
*
@@ -55,7 +61,7 @@ public function __construct(
}
/**
- * Processes value using backend model.
+ * Processes value to display using backend model.
*
* @param string $scope The scope of configuration. E.g. 'default', 'website' or 'store'
* @param string $scopeCode The scope code of configuration
@@ -78,6 +84,11 @@ public function process($scope, $scopeCode, $value, $path)
$backendModel = $field && $field->hasBackendModel()
? $field->getBackendModel()
: $this->configValueFactory->create();
+
+ if ($backendModel instanceof Encrypted) {
+ return $value ? self::SAFE_PLACEHOLDER : null;
+ }
+
$backendModel->setPath($path);
$backendModel->setScope($scope);
$backendModel->setScopeId($scopeCode);
diff --git a/app/code/Magento/Config/Console/Command/ConfigShowCommand.php b/app/code/Magento/Config/Console/Command/ConfigShowCommand.php
index 5003b0eab725b..17ad5aa199a2a 100644
--- a/app/code/Magento/Config/Console/Command/ConfigShowCommand.php
+++ b/app/code/Magento/Config/Console/Command/ConfigShowCommand.php
@@ -144,7 +144,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
try {
$this->scope = $input->getOption(self::INPUT_OPTION_SCOPE);
$this->scopeCode = $input->getOption(self::INPUT_OPTION_SCOPE_CODE);
- $this->inputPath = $input->getArgument(self::INPUT_ARGUMENT_PATH);
+ $this->inputPath = trim($input->getArgument(self::INPUT_ARGUMENT_PATH), '/');
$this->scopeValidator->isValid($this->scope, $this->scopeCode);
$configPath = $this->pathResolver->resolve($this->inputPath, $this->scope, $this->scopeCode);
diff --git a/app/code/Magento/Config/Model/Config/PathValidator.php b/app/code/Magento/Config/Model/Config/PathValidator.php
new file mode 100644
index 0000000000000..49838c5dcb88d
--- /dev/null
+++ b/app/code/Magento/Config/Model/Config/PathValidator.php
@@ -0,0 +1,47 @@
+structure = $structure;
+ }
+
+ /**
+ * Checks whether the config path present in configuration structure.
+ *
+ * @param string $path The config path
+ * @return true The result of validation
+ * @throws ValidatorException If provided path is not valid
+ */
+ public function validate($path)
+ {
+ $allPaths = $this->structure->getFieldPaths();
+
+ if (!array_key_exists($path, $allPaths)) {
+ throw new ValidatorException(__('The "%1" path does not exist', $path));
+ }
+
+ return true;
+ }
+}
diff --git a/app/code/Magento/Config/Model/Config/Structure.php b/app/code/Magento/Config/Model/Config/Structure.php
index 9368f48f3a6ba..7f026adca3ce6 100644
--- a/app/code/Magento/Config/Model/Config/Structure.php
+++ b/app/code/Magento/Config/Model/Config/Structure.php
@@ -3,12 +3,11 @@
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+namespace Magento\Config\Model\Config;
/**
- * System configuration structure
+ * System configuration structure.
*/
-namespace Magento\Config\Model\Config;
-
class Structure implements \Magento\Config\Model\Config\Structure\SearchInterface
{
/**
@@ -251,4 +250,80 @@ protected function _getGroupFieldPathsByAttribute(array $fields, $parentPath, $a
}
return $result;
}
+
+ /**
+ * Collects config paths and their structure paths from configuration files.
+ * Returns the map of config paths and their structure paths.
+ *
+ * All paths are declared in module's system.xml.
+ *
+ * ```xml
+ *
+ *
+ *
+ *
+ * ...
+ *
+ *
+ *
+ * section/group/field
+ * ...
+ *
+ *
+ *
+ * ```
+ * If node does not exist, then config path duplicates structure path.
+ * The result of this example will be:
+ *
+ * ```php
+ * [
+ * 'section_id/group_id/field_one_id' => [
+ * 'section_id/group_id/field_one_id'
+ * ],
+ * 'section/group/field' => [
+ * 'section_id/group_id/field_two_id'
+ * ]
+ *```
+ *
+ * @return array An array of config path to config structure path map
+ */
+ public function getFieldPaths()
+ {
+ $sections = !empty($this->_data['sections']) ? $this->_data['sections'] : [];
+
+ return $this->getFieldsRecursively($sections);
+ }
+
+ /**
+ * Iteration that collects config field paths recursively from config files.
+ *
+ * @param array $elements The elements to be parsed
+ * @return array An array of config path to config structure path map
+ */
+ private function getFieldsRecursively(array $elements = [])
+ {
+ $result = [];
+
+ foreach ($elements as $element) {
+ if (isset($element['children'])) {
+ $result = array_replace_recursive(
+ $result,
+ $this->getFieldsRecursively($element['children'])
+ );
+ } else {
+ if ($element['_elementType'] === 'field' && isset($element['label'])) {
+ $structurePath = (isset($element['path']) ? $element['path'] . '/' : '') . $element['id'];
+ $configPath = isset($element['config_path']) ? $element['config_path'] : $structurePath;
+
+ if (!isset($result[$configPath])) {
+ $result[$configPath] = [];
+ }
+
+ $result[$configPath][] = $structurePath;
+ }
+ }
+ }
+
+ return $result;
+ }
}
diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php
index 1ac9892f0f923..8c837baf14878 100644
--- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php
+++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php
@@ -164,7 +164,7 @@ public function testProcess($path, $value, $scope, $scopeCode)
->method('saveConfig')
->with(
[
- ConfigFilePool::APP_CONFIG => [
+ ConfigFilePool::APP_ENV => [
'system' => [
'default' => [
'test' => [
@@ -234,7 +234,7 @@ public function testProcessBackendModelNotExists()
->method('saveConfig')
->with(
[
- ConfigFilePool::APP_CONFIG => [
+ ConfigFilePool::APP_ENV => [
'system' => [
'default' => [
'test' => [
diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php
index 1f4f30023c157..1a417073548b2 100644
--- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php
+++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php
@@ -8,10 +8,13 @@
use Magento\Config\Console\Command\ConfigSet\ConfigSetProcessorFactory;
use Magento\Config\Console\Command\ConfigSet\ConfigSetProcessorInterface;
use Magento\Config\Console\Command\ConfigSetCommand;
+use Magento\Config\Model\Config\PathValidator;
+use Magento\Config\Model\Config\PathValidatorFactory;
use Magento\Framework\App\Scope\ValidatorInterface;
use Magento\Framework\Config\ScopeInterface;
use Magento\Framework\Console\Cli;
use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Exception\ValidatorException;
use PHPUnit_Framework_MockObject_MockObject as Mock;
use Symfony\Component\Console\Tester\CommandTester;
@@ -48,6 +51,16 @@ class ConfigSetCommandTest extends \PHPUnit_Framework_TestCase
*/
private $scopeMock;
+ /**
+ * @var PathValidatorFactory|Mock
+ */
+ private $pathValidatorFactoryMock;
+
+ /**
+ * @var PathValidator|Mock
+ */
+ private $pathValidator;
+
/**
* @inheritdoc
*/
@@ -63,11 +76,23 @@ protected function setUp()
->getMockForAbstractClass();
$this->scopeMock = $this->getMockBuilder(ScopeInterface::class)
->getMockForAbstractClass();
+ $this->pathValidatorFactoryMock = $this->getMockBuilder(PathValidatorFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->pathValidator = $this->getMockBuilder(PathValidator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->pathValidatorFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($this->pathValidator);
$this->command = new ConfigSetCommand(
$this->configSetProcessorFactoryMock,
$this->validatorMock,
- $this->scopeMock
+ $this->scopeMock,
+ $this->pathValidatorFactoryMock
);
}
@@ -120,4 +145,28 @@ public function testExecuteNotValidScope()
$this->assertSame(Cli::RETURN_FAILURE, $tester->getStatusCode());
}
+
+ public function testExecuteWithException()
+ {
+ $this->validatorMock->expects($this->once())
+ ->method('isValid')
+ ->willReturn(true);
+ $this->pathValidator->expects($this->once())
+ ->method('validate')
+ ->willThrowException(new ValidatorException(__('The "test/test/test" path does not exists')));
+ $this->configSetProcessorFactoryMock->expects($this->never())
+ ->method('create');
+
+ $tester = new CommandTester($this->command);
+ $tester->execute([
+ ConfigSetCommand::ARG_PATH => 'test/test/test',
+ ConfigSetCommand::ARG_VALUE => 'value'
+ ]);
+
+ $this->assertContains(
+ __('The "test/test/test" path does not exists')->render(),
+ $tester->getDisplay()
+ );
+ $this->assertSame(Cli::RETURN_FAILURE, $tester->getStatusCode());
+ }
}
diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigShow/ValueProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigShow/ValueProcessorTest.php
index 85eb78ba7380e..1aa8092390caa 100644
--- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigShow/ValueProcessorTest.php
+++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigShow/ValueProcessorTest.php
@@ -13,7 +13,13 @@
use Magento\Framework\Config\ScopeInterface;
use Magento\Framework\App\Area;
use Magento\Config\Console\Command\ConfigShow\ValueProcessor;
+use Magento\Config\Model\Config\Backend\Encrypted;
+/**
+ * Test for ValueProcessor.
+ *
+ * @see ValueProcessor
+ */
class ValueProcessorTest extends \PHPUnit_Framework_TestCase
{
/**
@@ -59,13 +65,34 @@ protected function setUp()
* @param bool $hasBackendModel
* @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsGetBackendModel
* @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsCreate
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsGetValue
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsSetPath
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsSetScope
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsSetScopeId
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsSetValue
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsAfterLoad
+ * @param string $expectsValue
+ * @param string $className
+ * @param string $value
* @dataProvider processDataProvider
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
- public function testProcess($hasBackendModel, $expectsGetBackendModel, $expectsCreate)
- {
+ public function testProcess(
+ $hasBackendModel,
+ $expectsGetBackendModel,
+ $expectsCreate,
+ $expectsGetValue,
+ $expectsSetPath,
+ $expectsSetScope,
+ $expectsSetScopeId,
+ $expectsSetValue,
+ $expectsAfterLoad,
+ $expectsValue,
+ $className,
+ $value
+ ) {
$scope = 'someScope';
$scopeCode = 'someScopeCode';
- $value = 'someValue';
$path = 'some/config/path';
$oldConfigScope = 'oldConfigScope';
@@ -87,31 +114,31 @@ public function testProcess($hasBackendModel, $expectsGetBackendModel, $expectsC
->method('create')
->willReturn($structureMock);
- /** @var Value|\PHPUnit_Framework_MockObject_MockObject $valueMock */
- $backendModelMock = $this->getMockBuilder(Value::class)
+ /** @var Value|Encrypted|\PHPUnit_Framework_MockObject_MockObject $valueMock */
+ $backendModelMock = $this->getMockBuilder($className)
->disableOriginalConstructor()
->setMethods(['setPath', 'setScope', 'setScopeId', 'setValue', 'getValue', 'afterLoad'])
->getMock();
- $backendModelMock->expects($this->once())
+ $backendModelMock->expects($expectsSetPath)
->method('setPath')
->with($path)
->willReturnSelf();
- $backendModelMock->expects($this->once())
+ $backendModelMock->expects($expectsSetScope)
->method('setScope')
->with($scope)
->willReturnSelf();
- $backendModelMock->expects($this->once())
+ $backendModelMock->expects($expectsSetScopeId)
->method('setScopeId')
->with($scopeCode)
->willReturnSelf();
- $backendModelMock->expects($this->once())
+ $backendModelMock->expects($expectsSetValue)
->method('setValue')
->with($value)
->willReturnSelf();
- $backendModelMock->expects($this->once())
+ $backendModelMock->expects($expectsAfterLoad)
->method('afterLoad')
->willReturnSelf();
- $backendModelMock->expects($this->once())
+ $backendModelMock->expects($expectsGetValue)
->method('getValue')
->willReturn($value);
@@ -134,17 +161,86 @@ public function testProcess($hasBackendModel, $expectsGetBackendModel, $expectsC
->with($path)
->willReturn($fieldMock);
- $this->assertSame($value, $this->valueProcessor->process($scope, $scopeCode, $value, $path));
+ $this->assertSame($expectsValue, $this->valueProcessor->process($scope, $scopeCode, $value, $path));
}
/**
* @return array
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function processDataProvider()
{
return [
- ['hasBackendModel' => true, 'expectsGetBackendModel' => $this->once(), 'expectsCreate' => $this->never()],
- ['hasBackendModel' => false, 'expectsGetBackendModel' => $this->never(), 'expectsCreate' => $this->once()],
+ [
+ 'hasBackendModel' => true,
+ 'expectsGetBackendModel' => $this->once(),
+ 'expectsCreate' => $this->never(),
+ 'expectsGetValue' => $this->once(),
+ 'expectsSetPath' => $this->once(),
+ 'expectsSetScope' => $this->once(),
+ 'expectsSetScopeId' => $this->once(),
+ 'expectsSetValue' => $this->once(),
+ 'expectsAfterLoad' => $this->once(),
+ 'expectsValue' => 'someValue',
+ 'className' => Value::class,
+ 'value' => 'someValue'
+ ],
+ [
+ 'hasBackendModel' => false,
+ 'expectsGetBackendModel' => $this->never(),
+ 'expectsCreate' => $this->once(),
+ 'expectsGetValue' => $this->once(),
+ 'expectsSetPath' => $this->once(),
+ 'expectsSetScope' => $this->once(),
+ 'expectsSetScopeId' => $this->once(),
+ 'expectsSetValue' => $this->once(),
+ 'expectsAfterLoad' => $this->once(),
+ 'expectsValue' => 'someValue',
+ 'className' => Value::class,
+ 'value' => 'someValue'
+ ],
+ [
+ 'hasBackendModel' => true,
+ 'expectsGetBackendModel' => $this->once(),
+ 'expectsCreate' => $this->never(),
+ 'expectsGetValue' => $this->never(),
+ 'expectsSetPath' => $this->never(),
+ 'expectsSetScope' => $this->never(),
+ 'expectsSetScopeId' => $this->never(),
+ 'expectsSetValue' => $this->never(),
+ 'expectsAfterLoad' => $this->never(),
+ 'expectsValue' => ValueProcessor::SAFE_PLACEHOLDER,
+ 'className' => Encrypted::class,
+ 'value' => 'someValue'
+ ],
+ [
+ 'hasBackendModel' => true,
+ 'expectsGetBackendModel' => $this->once(),
+ 'expectsCreate' => $this->never(),
+ 'expectsGetValue' => $this->once(),
+ 'expectsSetPath' => $this->once(),
+ 'expectsSetScope' => $this->once(),
+ 'expectsSetScopeId' => $this->once(),
+ 'expectsSetValue' => $this->once(),
+ 'expectsAfterLoad' => $this->once(),
+ 'expectsValue' => null,
+ 'className' => Value::class,
+ 'value' => null
+ ],
+ [
+ 'hasBackendModel' => true,
+ 'expectsGetBackendModel' => $this->once(),
+ 'expectsCreate' => $this->never(),
+ 'expectsGetValue' => $this->never(),
+ 'expectsSetPath' => $this->never(),
+ 'expectsSetScope' => $this->never(),
+ 'expectsSetScopeId' => $this->never(),
+ 'expectsSetValue' => $this->never(),
+ 'expectsAfterLoad' => $this->never(),
+ 'expectsValue' => null,
+ 'className' => Encrypted::class,
+ 'value' => null
+ ],
];
}
}
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/PathValidatorTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/PathValidatorTest.php
new file mode 100644
index 0000000000000..e6e5e74047440
--- /dev/null
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/PathValidatorTest.php
@@ -0,0 +1,68 @@
+structureMock = $this->getMockBuilder(Structure::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->model = new PathValidator(
+ $this->structureMock
+ );
+ }
+
+ public function testValidate()
+ {
+ $this->structureMock->expects($this->once())
+ ->method('getFieldPaths')
+ ->willReturn([
+ 'test/test/test' => [
+ 'test/test/test'
+ ]
+ ]);
+
+ $this->assertTrue($this->model->validate('test/test/test'));
+ }
+
+ /**
+ * @expectedException \Magento\Framework\Exception\ValidatorException
+ * @expectedExceptionMessage The "test/test/test" path does not exist
+ */
+ public function testValidateWithException()
+ {
+ $this->structureMock->expects($this->once())
+ ->method('getFieldPaths')
+ ->willReturn([]);
+
+ $this->assertTrue($this->model->validate('test/test/test'));
+ }
+}
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/StructureTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/StructureTest.php
index 2f7c2a1e659b4..6442a49dc181e 100644
--- a/app/code/Magento/Config/Test/Unit/Model/Config/StructureTest.php
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/StructureTest.php
@@ -4,34 +4,44 @@
* See COPYING.txt for license details.
*/
-// @codingStandardsIgnoreFile
-
namespace Magento\Config\Test\Unit\Model\Config;
+use Magento\Config\Model\Config\ScopeDefiner;
+use Magento\Config\Model\Config\Structure;
+use Magento\Config\Model\Config\Structure\Data;
+use Magento\Config\Model\Config\Structure\Element\FlyweightFactory;
+use Magento\Config\Model\Config\Structure\Element\Iterator\Tab as TabIterator;
+use PHPUnit_Framework_MockObject_MockObject as Mock;
+
+/**
+ * Test for Structure.
+ *
+ * @see Structure
+ */
class StructureTest extends \PHPUnit_Framework_TestCase
{
/**
- * @var \Magento\Config\Model\Config\Structure
+ * @var Structure|Mock
*/
protected $_model;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var FlyweightFactory|Mock
*/
protected $_flyweightFactory;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var TabIterator|Mock
*/
protected $_tabIteratorMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var Data|Mock
*/
protected $_structureDataMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var ScopeDefiner|Mock
*/
protected $_scopeDefinerMock;
@@ -42,46 +52,29 @@ class StructureTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
- $this->_flyweightFactory = $this->getMock(
- \Magento\Config\Model\Config\Structure\Element\FlyweightFactory::class,
- [],
- [],
- '',
- false
- );
- $this->_tabIteratorMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Element\Iterator\Tab::class,
- [],
- [],
- '',
- false
- );
- $this->_structureDataMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Data::class,
- [],
- [],
- '',
- false
- );
- $this->_scopeDefinerMock = $this->getMock(
- \Magento\Config\Model\Config\ScopeDefiner::class,
- [],
- [],
- '',
- false
- );
- $this->_scopeDefinerMock->expects($this->any())->method('getScope')->will($this->returnValue('scope'));
-
- $filePath = dirname(__DIR__) . '/_files';
- $this->_structureData = require $filePath . '/converted_config.php';
- $this->_structureDataMock->expects(
- $this->once()
- )->method(
- 'get'
- )->will(
- $this->returnValue($this->_structureData['config']['system'])
- );
- $this->_model = new \Magento\Config\Model\Config\Structure(
+ $this->_flyweightFactory = $this->getMockBuilder(FlyweightFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->_tabIteratorMock = $this->getMockBuilder(TabIterator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->_structureDataMock = $this->getMockBuilder(Data::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->_scopeDefinerMock = $this->getMockBuilder(ScopeDefiner::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->_structureData = require dirname(__DIR__) . '/_files/converted_config.php';
+
+ $this->_scopeDefinerMock->expects($this->any())
+ ->method('getScope')
+ ->willReturn('scope');
+ $this->_structureDataMock->expects($this->once())
+ ->method('get')
+ ->willReturn($this->_structureData['config']['system']);
+
+ $this->_model = new Structure(
$this->_structureDataMock,
$this->_tabIteratorMock,
$this->_flyweightFactory,
@@ -89,60 +82,47 @@ protected function setUp()
);
}
- protected function tearDown()
- {
- unset($this->_flyweightFactory);
- unset($this->_scopeDefinerMock);
- unset($this->_structureData);
- unset($this->_tabIteratorMock);
- unset($this->_structureDataMock);
- unset($this->_model);
- }
-
public function testGetTabsBuildsSectionTree()
{
- $this->_structureDataMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Data::class,
- [],
- [],
- '',
- false
- );
- $this->_structureDataMock->expects(
- $this->any()
- )->method(
- 'get'
- )->will(
- $this->returnValue(
- ['sections' => ['section1' => ['tab' => 'tab1']], 'tabs' => ['tab1' => []]]
- )
- );
$expected = ['tab1' => ['children' => ['section1' => ['tab' => 'tab1']]]];
+
+ $this->_structureDataMock = $this->getMockBuilder(Data::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->_structureDataMock->expects($this->any())
+ ->method('get')
+ ->willReturn(
+ ['sections' => ['section1' => ['tab' => 'tab1']], 'tabs' => ['tab1' => []]]
+ );
+ $this->_tabIteratorMock->expects($this->once())
+ ->method('setElements')
+ ->with($expected);
+
$model = new \Magento\Config\Model\Config\Structure(
$this->_structureDataMock,
$this->_tabIteratorMock,
$this->_flyweightFactory,
$this->_scopeDefinerMock
);
- $this->_tabIteratorMock->expects($this->once())->method('setElements')->with($expected);
+
$this->assertEquals($this->_tabIteratorMock, $model->getTabs());
}
public function testGetSectionList()
{
- $this->_structureDataMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Data::class,
- [],
- [],
- '',
- false
- );
- $this->_structureDataMock->expects(
- $this->any()
- )->method(
- 'get'
- )->will(
- $this->returnValue(
+ $expected = [
+ 'section1_child_id_1' => true,
+ 'section1_child_id_2' => true,
+ 'section1_child_id_3' => true,
+ 'section2_child_id_1' => true
+ ];
+
+ $this->_structureDataMock = $this->getMockBuilder(Data::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->_structureDataMock->expects($this->any())
+ ->method('get')
+ ->willReturn(
[
'sections' => [
'section1' => [
@@ -159,14 +139,8 @@ public function testGetSectionList()
],
]
]
- )
- );
- $expected = [
- 'section1_child_id_1' => true,
- 'section1_child_id_2' => true,
- 'section1_child_id_3' => true,
- 'section2_child_id_1' => true
- ];
+ );
+
$model = new \Magento\Config\Model\Config\Structure(
$this->_structureDataMock,
$this->_tabIteratorMock,
@@ -191,17 +165,17 @@ public function testGetElementReturnsEmptyElementIfNotExistingElementIsRequested
$expectedPath
) {
$expectedConfig = ['id' => $expectedId, 'path' => $expectedPath, '_elementType' => $expectedType];
- $elementMock = $this->getMock(\Magento\Config\Model\Config\Structure\ElementInterface::class);
- $elementMock->expects($this->once())->method('setData')->with($expectedConfig);
- $this->_flyweightFactory->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- $expectedType
- )->will(
- $this->returnValue($elementMock)
- );
+
+ $elementMock = $this->getMockBuilder(Structure\ElementInterface::class)
+ ->getMockForAbstractClass();
+ $elementMock->expects($this->once())
+ ->method('setData')
+ ->with($expectedConfig);
+ $this->_flyweightFactory->expects($this->once())
+ ->method('create')
+ ->with($expectedType)
+ ->willReturn($elementMock);
+
$this->assertEquals($elementMock, $this->_model->getElement($path));
}
@@ -217,121 +191,102 @@ public function emptyElementDataProvider()
public function testGetElementReturnsProperElementByPath()
{
- $elementMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Element\Field::class,
- [],
- [],
- '',
- false
- );
$section = $this->_structureData['config']['system']['sections']['section_1'];
$fieldData = $section['children']['group_level_1']['children']['field_3'];
- $elementMock->expects($this->once())->method('setData')->with($fieldData, 'scope');
-
- $this->_flyweightFactory->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- 'field'
- )->will(
- $this->returnValue($elementMock)
- );
+
+ $elementMock = $this->getMockBuilder(Structure\Element\Field::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $elementMock->expects($this->once())
+ ->method('setData')
+ ->with($fieldData, 'scope');
+ $this->_flyweightFactory->expects($this->once())
+ ->method('create')
+ ->with('field')
+ ->willReturn($elementMock);
+
$this->assertEquals($elementMock, $this->_model->getElement('section_1/group_level_1/field_3'));
}
public function testGetElementByPathPartsIfSectionDataIsEmpty()
{
- $elementMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Element\Field::class,
- [],
- [],
- '',
- false
- );
$fieldData = [
'id' => 'field_3',
'path' => 'section_1/group_level_1',
'_elementType' => 'field',
];
- $elementMock->expects($this->once())->method('setData')->with($fieldData, 'scope');
-
- $this->_flyweightFactory->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- 'field'
- )->will(
- $this->returnValue($elementMock)
- );
+ $pathParts = explode('/', 'section_1/group_level_1/field_3');
- $structureDataMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Data::class,
- [],
- [],
- '',
- false
- );
+ $elementMock = $this->getMockBuilder(Structure\Element\Field::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $structureDataMock = $this->getMockBuilder(Data::class)
+ ->disableOriginalConstructor()
+ ->getMock();
- $structureDataMock->expects(
- $this->once()
- )->method(
- 'get'
- )->will(
- $this->returnValue([])
- );
+ $elementMock->expects($this->once())
+ ->method('setData')
+ ->with($fieldData, 'scope');
+ $this->_flyweightFactory->expects($this->once())
+ ->method('create')
+ ->with('field')
+ ->willReturn($elementMock);
+ $structureDataMock->expects($this->once())
+ ->method('get')
+ ->willReturn([]);
- $structureMock = new \Magento\Config\Model\Config\Structure(
+ $structureMock = new Structure(
$structureDataMock,
$this->_tabIteratorMock,
$this->_flyweightFactory,
$this->_scopeDefinerMock
);
- $pathParts = explode('/', 'section_1/group_level_1/field_3');
$this->assertEquals($elementMock, $structureMock->getElementByPathParts($pathParts));
}
public function testGetFirstSectionReturnsFirstAllowedSection()
{
- $tabMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Element\Tab::class,
- ['current', 'getChildren', 'rewind'],
- [],
- '',
- false
- );
- $tabMock->expects($this->any())->method('getChildren')->will($this->returnSelf());
- $tabMock->expects($this->once())->method('rewind');
- $tabMock->expects($this->once())->method('current')->will($this->returnValue('currentSection'));
- $this->_tabIteratorMock->expects($this->once())->method('rewind');
- $this->_tabIteratorMock->expects($this->once())->method('current')->will($this->returnValue($tabMock));
+ $tabMock = $this->getMockBuilder(Structure\Element\Tab::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['current', 'getChildren', 'rewind'])
+ ->getMock();
+
+ $tabMock->expects($this->any())
+ ->method('getChildren')
+ ->willReturnSelf();
+ $tabMock->expects($this->once())
+ ->method('rewind');
+ $tabMock->expects($this->once())
+ ->method('current')
+ ->willReturn('currentSection');
+ $this->_tabIteratorMock->expects($this->once())
+ ->method('rewind');
+ $this->_tabIteratorMock->expects($this->once())
+ ->method('current')
+ ->willReturn($tabMock);
+
$this->assertEquals('currentSection', $this->_model->getFirstSection());
}
public function testGetElementReturnsProperElementByPathCachesObject()
{
- $elementMock = $this->getMock(
- \Magento\Config\Model\Config\Structure\Element\Field::class,
- [],
- [],
- '',
- false
- );
$section = $this->_structureData['config']['system']['sections']['section_1'];
$fieldData = $section['children']['group_level_1']['children']['field_3'];
- $elementMock->expects($this->once())->method('setData')->with($fieldData, 'scope');
-
- $this->_flyweightFactory->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- 'field'
- )->will(
- $this->returnValue($elementMock)
- );
+
+ $elementMock = $this->getMockBuilder(Structure\Element\Field::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $elementMock->expects($this->once())
+ ->method('setData')
+ ->with($fieldData, 'scope');
+ $this->_flyweightFactory->expects($this->once())
+ ->method('create')
+ ->with('field')
+ ->willReturn($elementMock);
+
$this->assertEquals($elementMock, $this->_model->getElement('section_1/group_level_1/field_3'));
$this->assertEquals($elementMock, $this->_model->getElement('section_1/group_level_1/field_3'));
}
@@ -350,12 +305,45 @@ public function testGetFieldPathsByAttribute($attributeName, $attributeValue, $p
public function getFieldPathsByAttributeDataProvider()
{
return [
- ['backend_model', \Magento\Config\Model\Config\Backend\Encrypted::class, [
- 'section_1/group_1/field_2',
- 'section_1/group_level_1/group_level_2/group_level_3/field_3_1_1',
- 'section_2/group_3/field_4',
- ]],
+ [
+ 'backend_model',
+ \Magento\Config\Model\Config\Backend\Encrypted::class,
+ [
+ 'section_1/group_1/field_2',
+ 'section_1/group_level_1/group_level_2/group_level_3/field_3_1_1',
+ 'section_2/group_3/field_4',
+ ]
+ ],
['attribute_2', 'test_value_2', ['section_2/group_3/field_4']]
];
}
+
+ public function testGetFieldPaths()
+ {
+ $expected = [
+ 'section/group/field2' => [
+ 'field_2'
+ ],
+ 'field_3' => [
+ 'field_3'
+ ],
+ 'field_3_1' => [
+ 'field_3_1'
+ ],
+ 'field_3_1_1' => [
+ 'field_3_1_1'
+ ],
+ 'section/group/field4' => [
+ 'field_4',
+ ],
+ 'field_5' => [
+ 'field_5',
+ ],
+ ];
+
+ $this->assertSame(
+ $expected,
+ $this->_model->getFieldPaths()
+ );
+ }
}
diff --git a/app/code/Magento/Config/Test/Unit/Model/_files/converted_config.php b/app/code/Magento/Config/Test/Unit/Model/_files/converted_config.php
index fb14e864b4fb0..e94e5bd881240 100644
--- a/app/code/Magento/Config/Test/Unit/Model/_files/converted_config.php
+++ b/app/code/Magento/Config/Test/Unit/Model/_files/converted_config.php
@@ -29,6 +29,7 @@
'children' => [
'field_2' => [
'id' => 'field_2',
+ 'config_path' => 'section/group/field2',
'translate' => 'label',
'showInWebsite' => '1',
'type' => 'text',
@@ -133,6 +134,7 @@
],
'field_4' => [
'id' => 'field_4',
+ 'config_path' => 'section/group/field4',
'translate' => 'label',
'showInWebsite' => '1',
'type' => 'text',
diff --git a/app/code/Magento/Config/Test/Unit/Model/_files/system_2.xml b/app/code/Magento/Config/Test/Unit/Model/_files/system_2.xml
index c532d3b784fe9..e04890c2c14e9 100644
--- a/app/code/Magento/Config/Test/Unit/Model/_files/system_2.xml
+++ b/app/code/Magento/Config/Test/Unit/Model/_files/system_2.xml
@@ -18,6 +18,7 @@
Magento\Config\Model\Config\Backend\Encrypted
+ section/group/field2
@@ -70,7 +71,9 @@
0
+
+ section/group/field4
diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml
index 3a716d50dbaa0..de1dcbdb4c39b 100644
--- a/app/code/Magento/Config/etc/di.xml
+++ b/app/code/Magento/Config/etc/di.xml
@@ -145,7 +145,6 @@
Magento\Framework\App\DeploymentConfig\Reader
Magento\Config\App\Config\Type\System::CONFIG_TYPE
- Magento\Framework\Config\File\ConfigFilePool::APP_CONFIG
@@ -201,7 +200,7 @@
- systemConfigInitialDataProvider
- 1000
- -
+
-
- Magento\Config\App\Config\Source\EnvironmentConfigSource
- 2000
diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php
index b63357be6bf8a..e2413f8061680 100644
--- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php
+++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php
@@ -12,6 +12,8 @@
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Deploy\Model\DeploymentConfig\Hash;
+use Magento\Framework\App\ObjectManager;
/**
* Command for dump application state
@@ -28,19 +30,27 @@ class ApplicationDumpCommand extends Command
*/
private $sources;
+ /**
+ * @var Hash
+ */
+ private $configHash;
+
/**
* ApplicationDumpCommand constructor.
*
* @param Writer $writer
* @param array $sources
+ * @param Hash $configHash
*/
public function __construct(
Writer $writer,
- array $sources
+ array $sources,
+ Hash $configHash = null
) {
parent::__construct();
$this->writer = $writer;
$this->sources = $sources;
+ $this->configHash = $configHash ?: ObjectManager::getInstance()->get(Hash::class);
}
/**
@@ -76,16 +86,19 @@ protected function execute(InputInterface $input, OutputInterface $output)
: $sourceData['comment']->get();
}
}
- $this->writer
- ->saveConfig(
- [ConfigFilePool::APP_CONFIG => $dump],
- true,
- ConfigFilePool::LOCAL,
- $comments
- );
+ $this->writer->saveConfig(
+ [ConfigFilePool::APP_CONFIG => $dump],
+ true,
+ null,
+ $comments
+ );
if (!empty($comments)) {
$output->writeln($comments);
}
+
+ // Generate and save new hash of deployment configuration.
+ $this->configHash->regenerate();
+
$output->writeln('Done.');
return Cli::RETURN_SUCCESS;
}
diff --git a/app/code/Magento/Deploy/Console/Command/App/ConfigImport/Importer.php b/app/code/Magento/Deploy/Console/Command/App/ConfigImport/Importer.php
new file mode 100644
index 0000000000000..c8802224aa874
--- /dev/null
+++ b/app/code/Magento/Deploy/Console/Command/App/ConfigImport/Importer.php
@@ -0,0 +1,111 @@
+configValidator = $configValidator;
+ $this->configImporterPool = $configImporterPool;
+ $this->deploymentConfig = $deploymentConfig;
+ $this->configHash = $configHash;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Runs importing of config data from deployment configuration files.
+ *
+ * @param OutputInterface $output the CLI output
+ * @return void
+ * @throws LocalizedException
+ */
+ public function import(OutputInterface $output)
+ {
+ $output->writeln('Start import:');
+
+ try {
+ $importers = $this->configImporterPool->getImporters();
+
+ if (!$importers || $this->configValidator->isValid()) {
+ $output->writeln('Nothing to import');
+ } else {
+ /**
+ * @var string $namespace
+ * @var ImporterInterface $importer
+ */
+ foreach ($importers as $namespace => $importer) {
+ $messages = $importer->import($this->deploymentConfig->getConfigData($namespace));
+ $output->writeln($messages);
+ }
+
+ $this->configHash->regenerate();
+ }
+ } catch (LocalizedException $exception) {
+ $this->logger->error($exception);
+ throw new LocalizedException(__('Import is failed'), $exception);
+ }
+ }
+}
diff --git a/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php b/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php
new file mode 100644
index 0000000000000..809211c2314b8
--- /dev/null
+++ b/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php
@@ -0,0 +1,71 @@
+importer = $importer;
+
+ parent::__construct();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function configure()
+ {
+ $this->setName(self::COMMAND_NAME)
+ ->setDescription('Import data from shared configuration files to appropriate data storage');
+
+ parent::configure();
+ }
+
+ /**
+ * Imports data from deployment configuration files to the DB.
+ * {@inheritdoc}
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ try {
+ $this->importer->import($output);
+ } catch (LocalizedException $e) {
+ $output->writeln('' . $e->getMessage() . '');
+
+ return Cli::RETURN_FAILURE;
+ }
+
+ return Cli::RETURN_SUCCESS;
+ }
+}
diff --git a/app/code/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommand.php b/app/code/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommand.php
index e8555ceb9530f..a1da0db311966 100644
--- a/app/code/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommand.php
+++ b/app/code/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommand.php
@@ -163,7 +163,7 @@ private function writeSuccessMessage(OutputInterface $output, $isInteractive)
$output->writeln(sprintf(
'Configuration value%s saved in app/etc/%s',
$isInteractive ? 's' : '',
- $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG)
+ $this->configFilePool->getPath(ConfigFilePool::APP_ENV)
));
}
@@ -175,7 +175,7 @@ private function writeSuccessMessage(OutputInterface $output, $isInteractive)
*/
private function getConfigPaths()
{
- $configFilePath = $this->configFilePool->getPathsByPool(ConfigFilePool::LOCAL)[ConfigFilePool::APP_CONFIG];
+ $configFilePath = $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG);
try {
$configPaths = $this->commentParser->execute($configFilePath);
} catch (FileSystemException $e) {
diff --git a/app/code/Magento/Deploy/Model/ConfigWriter.php b/app/code/Magento/Deploy/Model/ConfigWriter.php
index 7a9b70c528ac9..8713442c9b0b1 100644
--- a/app/code/Magento/Deploy/Model/ConfigWriter.php
+++ b/app/code/Magento/Deploy/Model/ConfigWriter.php
@@ -55,10 +55,9 @@ public function save(array $values, $scope = ScopeConfigInterface::SCOPE_TYPE_DE
$config = $this->setConfig($config, $fullConfigPath, $configValue);
}
- $this->writer
- ->saveConfig(
- [ConfigFilePool::APP_CONFIG => $config]
- );
+ $this->writer->saveConfig(
+ [ConfigFilePool::APP_ENV => $config]
+ );
}
/**
diff --git a/app/code/Magento/Deploy/Model/DeploymentConfig/DataCollector.php b/app/code/Magento/Deploy/Model/DeploymentConfig/DataCollector.php
new file mode 100644
index 0000000000000..63fb770d468aa
--- /dev/null
+++ b/app/code/Magento/Deploy/Model/DeploymentConfig/DataCollector.php
@@ -0,0 +1,95 @@
+
+ *
+ *
+ * - Magento\Store\Model\StoreImporter
+ *
+ *
+ *
+ * ```
+ * Example, how sections are stored with their config data in configuration files:
+ * ```php
+ * [
+ * 'scopes' => [...],
+ * 'system' => [...],
+ * 'themes' => [...],
+ * ...
+ * ]
+ * ```
+ *
+ * In here we define section "scopes" and its importer Magento\Store\Model\StoreImporter.
+ * The data of this section will be collected then will be used in importing process from the shared configuration
+ * files to appropriate application sources.
+ *
+ * @see \Magento\Deploy\Console\Command\App\ConfigImport\Importer::import()
+ * @see \Magento\Deploy\Model\DeploymentConfig\Hash::regenerate()
+ */
+class DataCollector
+{
+ /**
+ * Pool of all deployment configuration importers.
+ *
+ * @var ImporterPool
+ */
+ private $configImporterPool;
+
+ /**
+ * Application deployment configuration.
+ *
+ * @var DeploymentConfig
+ */
+ private $deploymentConfig;
+
+ /**
+ * @param ImporterPool $configImporterPool the pool of all deployment configuration importers
+ * @param DeploymentConfig $deploymentConfig the application deployment configuration
+ */
+ public function __construct(ImporterPool $configImporterPool, DeploymentConfig $deploymentConfig)
+ {
+ $this->configImporterPool = $configImporterPool;
+ $this->deploymentConfig = $deploymentConfig;
+ }
+
+ /**
+ * Retrieves configuration data of specific section from deployment configuration files.
+ *
+ * E.g.
+ * ```php
+ * [
+ * 'scopes' => [...],
+ * 'system' => [...],
+ * 'themes' => [...],
+ * ...
+ * ]
+ * ```
+ * In this example key of the array is the section name, value of the array is configuration data of the section.
+ *
+ * @return array
+ */
+ public function getConfig()
+ {
+ $result = [];
+
+ foreach ($this->configImporterPool->getSections() as $section) {
+ $data = $this->deploymentConfig->getConfigData($section);
+ if ($data) {
+ $result[$section] = $data;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Deploy/Model/DeploymentConfig/Hash.php b/app/code/Magento/Deploy/Model/DeploymentConfig/Hash.php
new file mode 100644
index 0000000000000..6a904e9004a35
--- /dev/null
+++ b/app/code/Magento/Deploy/Model/DeploymentConfig/Hash.php
@@ -0,0 +1,103 @@
+deploymentConfig = $deploymentConfig;
+ $this->writer = $writer;
+ $this->configHashGenerator = $configHashGenerator;
+ $this->dataConfigCollector = $dataConfigCollector;
+ }
+
+ /**
+ * Updates hash in the storage.
+ *
+ * The hash is generated based on data from configuration files
+ *
+ * @return void
+ * @throws LocalizedException is thrown when hash was not saved
+ */
+ public function regenerate()
+ {
+ try {
+ $config = $this->dataConfigCollector->getConfig();
+ $hash = $this->configHashGenerator->generate($config);
+ $this->writer->saveConfig([ConfigFilePool::APP_ENV => [self::CONFIG_KEY => $hash]]);
+ } catch (FileSystemException $exception) {
+ throw new LocalizedException(__('Hash has not been saved'), $exception);
+ }
+ }
+
+ /**
+ * Retrieves saved hash from storage.
+ *
+ * @return string|null
+ */
+ public function get()
+ {
+ return $this->deploymentConfig->getConfigData(self::CONFIG_KEY);
+ }
+}
diff --git a/app/code/Magento/Deploy/Model/DeploymentConfig/Hash/Generator.php b/app/code/Magento/Deploy/Model/DeploymentConfig/Hash/Generator.php
new file mode 100644
index 0000000000000..896460861ebd9
--- /dev/null
+++ b/app/code/Magento/Deploy/Model/DeploymentConfig/Hash/Generator.php
@@ -0,0 +1,40 @@
+serializer = $serializer;
+ }
+
+ /**
+ * Generates and retrieves hash of deployment configuration data.
+ *
+ * @param array|string $data the deployment configuration data from files
+ * @return string the hash
+ */
+ public function generate($data)
+ {
+ return sha1($this->serializer->serialize($data));
+ }
+}
diff --git a/app/code/Magento/Deploy/Model/DeploymentConfig/ImporterPool.php b/app/code/Magento/Deploy/Model/DeploymentConfig/ImporterPool.php
new file mode 100644
index 0000000000000..b2b2fece8a192
--- /dev/null
+++ b/app/code/Magento/Deploy/Model/DeploymentConfig/ImporterPool.php
@@ -0,0 +1,124 @@
+
+ *
+ *
+ * - Magento\Store\Model\StoreImporter
+ *
+ *
+ *
+ * ```
+ *
+ * The example of section in deployment configuration file:
+ * ```php
+ * [
+ * 'scopes' => [
+ * 'websites' => [
+ * ...
+ * ],
+ * 'groups' => [
+ * ...
+ * ],
+ * 'stores' => [
+ * ...
+ * ],
+ * ...
+ * ]
+ * ]
+ * ```
+ *
+ * @var array
+ */
+ private $importers = [];
+
+ /**
+ * Magento object manager.
+ *
+ * @var ObjectManagerInterface
+ */
+ private $objectManager;
+
+ /**
+ * @param ObjectManagerInterface $objectManager the Magento object manager
+ * @param array $importers the list of sections and their importers
+ */
+ public function __construct(ObjectManagerInterface $objectManager, array $importers = [])
+ {
+ $this->objectManager = $objectManager;
+ $this->importers = $importers;
+ }
+
+ /**
+ * Retrieves names of sections for configuration files whose data is read from these files for import
+ * to appropriate application sources.
+ *
+ * @return array the list of sections
+ * E.g.
+ * ```php
+ * [
+ * 'scopes',
+ * 'themes',
+ * ...
+ * ]
+ * ```
+ */
+ public function getSections()
+ {
+ return array_keys($this->importers);
+ }
+
+ /**
+ * Retrieves list of all sections with their importer instances.
+ *
+ * E.g.
+ * ```php
+ * [
+ * 'scopes' => SomeScopeImporter(),
+ * ...
+ * ]
+ * ```
+ *
+ * @return array the list of all sections with their importer instances
+ * @throws ConfigurationMismatchException is thrown when instance of importer implements a wrong interface
+ */
+ public function getImporters()
+ {
+ $result = [];
+
+ foreach ($this->importers as $section => $importer) {
+ $importerObj = $this->objectManager->get($importer);
+ if (!$importerObj instanceof ImporterInterface) {
+ throw new ConfigurationMismatchException(new Phrase(
+ '%1: Instance of %2 is expected, got %3 instead',
+ [$section, ImporterInterface::class, get_class($importerObj)]
+ ));
+ }
+ $result[$section] = $importerObj;
+ }
+
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Deploy/Model/DeploymentConfig/Validator.php b/app/code/Magento/Deploy/Model/DeploymentConfig/Validator.php
new file mode 100644
index 0000000000000..7f6df6efdec19
--- /dev/null
+++ b/app/code/Magento/Deploy/Model/DeploymentConfig/Validator.php
@@ -0,0 +1,74 @@
+configHash = $configHash;
+ $this->hashGenerator = $hashGenerator;
+ $this->dataConfigCollector = $dataConfigCollector;
+ }
+
+ /**
+ * Checks if config data in the deployment configuration files is valid.
+ *
+ * Checks if config data was changed based on its hash.
+ * If the new hash of config data and the saved hash are different returns false.
+ * If config data is empty always returns true.
+ * In the other cases returns true.
+ *
+ * @return bool
+ */
+ public function isValid()
+ {
+ $config = $this->dataConfigCollector->getConfig();
+
+ if (!$config) {
+ return true;
+ }
+
+ return $this->hashGenerator->generate($config) === $this->configHash->get();
+ }
+}
diff --git a/app/code/Magento/Deploy/Model/Mode.php b/app/code/Magento/Deploy/Model/Mode.php
index 8052a27e2dbca..ba56a1c9006bf 100644
--- a/app/code/Magento/Deploy/Model/Mode.php
+++ b/app/code/Magento/Deploy/Model/Mode.php
@@ -122,7 +122,7 @@ public function enableDeveloperMode()
*/
public function getMode()
{
- $env = $this->reader->load(ConfigFilePool::APP_ENV);
+ $env = $this->reader->load();
return isset($env[State::PARAM_MODE]) ? $env[State::PARAM_MODE] : null;
}
diff --git a/app/code/Magento/Deploy/Model/Plugin/ConfigValidator.php b/app/code/Magento/Deploy/Model/Plugin/ConfigValidator.php
new file mode 100644
index 0000000000000..f5fc2bdc46dcb
--- /dev/null
+++ b/app/code/Magento/Deploy/Model/Plugin/ConfigValidator.php
@@ -0,0 +1,57 @@
+configValidator = $configValidator;
+ }
+
+ /**
+ * Performs check that config data from deployment configuration files is valid.
+ *
+ * @param FrontController $subject the object of controller is wrapped by this plugin
+ * @param RequestInterface $request the object that contains request params
+ * @return void
+ * @throws LocalizedException is thrown if config data from deployment configuration files is not valid
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeDispatch(FrontController $subject, RequestInterface $request)
+ {
+ if (!$this->configValidator->isValid()) {
+ throw new LocalizedException(
+ __(
+ 'A change in configuration has been detected.'
+ . ' Run app:config:import or setup:upgrade command to synchronize configuration.'
+ )
+ );
+ }
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImport/ImporterTest.php b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImport/ImporterTest.php
new file mode 100644
index 0000000000000..58ccf22eda71e
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImport/ImporterTest.php
@@ -0,0 +1,191 @@
+configValidatorMock = $this->getMockBuilder(Validator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->configImporterPoolMock = $this->getMockBuilder(ImporterPool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->configHashMock = $this->getMockBuilder(Hash::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->loggerMock = $this->getMockBuilder(Logger::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->outputMock = $this->getMockBuilder(OutputInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->importer = new Importer(
+ $this->configValidatorMock,
+ $this->configImporterPoolMock,
+ $this->deploymentConfigMock,
+ $this->configHashMock,
+ $this->loggerMock
+ );
+ }
+
+ /**
+ * @return void
+ */
+ public function testImport()
+ {
+ $configData = ['some data'];
+ $messages = ['Import has done'];
+ $expectsMessages = ['Import has done'];
+ $importerMock = $this->getMockBuilder(ImporterInterface::class)
+ ->getMockForAbstractClass();
+ $importers = ['someSection' => $importerMock];
+
+ $this->configImporterPoolMock->expects($this->once())
+ ->method('getImporters')
+ ->willReturn($importers);
+ $this->configValidatorMock->expects($this->any())
+ ->method('isValid')
+ ->willReturn(false);
+ $this->deploymentConfigMock->expects($this->once())
+ ->method('getConfigData')
+ ->with('someSection')
+ ->willReturn($configData);
+ $importerMock->expects($this->once())
+ ->method('import')
+ ->with($configData)
+ ->willReturn($messages);
+ $this->configHashMock->expects($this->once())
+ ->method('regenerate');
+ $this->loggerMock->expects($this->never())
+ ->method('error');
+
+ $this->outputMock->expects($this->at(0))
+ ->method('writeln')
+ ->with('Start import:');
+ $this->outputMock->expects($this->at(1))
+ ->method('writeln')
+ ->with($expectsMessages);
+
+ $this->importer->import($this->outputMock);
+ }
+
+ /**
+ * @return void
+ * @expectedException \Magento\Framework\Exception\LocalizedException
+ * @expectedExceptionMessage Import is failed
+ */
+ public function testImportWithException()
+ {
+ $exception = new LocalizedException(__('Some error'));
+ $this->outputMock->expects($this->at(0))
+ ->method('writeln')
+ ->with('Start import:');
+ $this->configImporterPoolMock->expects($this->once())
+ ->method('getImporters')
+ ->willThrowException($exception);
+ $this->loggerMock->expects($this->once())
+ ->method('error')
+ ->with($exception);
+
+ $this->importer->import($this->outputMock);
+ }
+
+ /**
+ * @param array $importers
+ * @param bool $isValid
+ * @return void
+ * @dataProvider importNothingToImportDataProvider
+ */
+ public function testImportNothingToImport(array $importers, $isValid)
+ {
+ $this->configImporterPoolMock->expects($this->once())
+ ->method('getImporters')
+ ->willReturn($importers);
+ $this->configValidatorMock->expects($this->any())
+ ->method('isValid')
+ ->willReturn($isValid);
+ $this->deploymentConfigMock->expects($this->never())
+ ->method('getConfigData');
+ $this->configHashMock->expects($this->never())
+ ->method('regenerate');
+ $this->loggerMock->expects($this->never())
+ ->method('error');
+
+ $this->outputMock->expects($this->at(0))
+ ->method('writeln')
+ ->with('Start import:');
+ $this->outputMock->expects($this->at(1))
+ ->method('writeln')
+ ->with('Nothing to import');
+
+ $this->importer->import($this->outputMock);
+ }
+
+ /**
+ * @return array
+ */
+ public function importNothingToImportDataProvider()
+ {
+ return [
+ ['importers' => [], 'isValid' => true],
+ ['importers' => [], 'isValid' => false],
+ ['importers' => ['someImporter'], 'isValid' => true],
+ ];
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php
new file mode 100644
index 0000000000000..f684615b1fb9a
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php
@@ -0,0 +1,65 @@
+importerMock = $this->getMockBuilder(Importer::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $configImportCommand = new ConfigImportCommand(
+ $this->importerMock
+ );
+
+ $this->commandTester = new CommandTester($configImportCommand);
+ }
+
+ /**
+ * @return void
+ */
+ public function testExecute()
+ {
+ $this->importerMock->expects($this->once())
+ ->method('import');
+
+ $this->assertSame(Cli::RETURN_SUCCESS, $this->commandTester->execute([]));
+ }
+
+ /**
+ * @return void
+ */
+ public function testExecuteWithException()
+ {
+ $this->importerMock->expects($this->once())
+ ->method('import')
+ ->willThrowException(new LocalizedException(__('Some error')));
+
+ $this->assertSame(Cli::RETURN_FAILURE, $this->commandTester->execute([]));
+ $this->assertContains('Some error', $this->commandTester->getDisplay());
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Console/Command/App/SensitiveConfigSetCommandTest.php b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/SensitiveConfigSetCommandTest.php
index 5a9b82a52d55b..215d3061d445d 100644
--- a/app/code/Magento/Deploy/Test/Unit/Console/Command/App/SensitiveConfigSetCommandTest.php
+++ b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/SensitiveConfigSetCommandTest.php
@@ -86,11 +86,9 @@ public function setUp()
public function testConfigFileNotExist()
{
$this->configFilePoolMock->expects($this->once())
- ->method('getPathsByPool')
- ->with(ConfigFilePool::LOCAL)
- ->willReturn([
- ConfigFilePool::APP_CONFIG => 'config.local.php'
- ]);
+ ->method('getPath')
+ ->with(ConfigFilePool::APP_CONFIG)
+ ->willReturn('config.php');
$this->scopeValidatorMock->expects($this->once())
->method('isValid')
->with('default', '')
@@ -110,7 +108,7 @@ public function testConfigFileNotExist()
$tester->getStatusCode()
);
$this->assertContains(
- 'File app/etc/config.local.php can\'t be read. '
+ 'File app/etc/config.php can\'t be read. '
. 'Please check if it exists and has read permissions.',
$tester->getDisplay()
);
diff --git a/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php b/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php
index c12c857c6c2c9..99a50d7227dc4 100644
--- a/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php
+++ b/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php
@@ -12,6 +12,7 @@
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Deploy\Model\DeploymentConfig\Hash;
/**
* Test command for dump application state
@@ -38,6 +39,11 @@ class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase
*/
private $source;
+ /**
+ * @var Hash|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $configHashMock;
+
/**
* @var ApplicationDumpCommand
*/
@@ -45,6 +51,9 @@ class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
+ $this->configHashMock = $this->getMockBuilder(Hash::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->input = $this->getMockBuilder(InputInterface::class)
->getMockForAbstractClass();
$this->output = $this->getMockBuilder(OutputInterface::class)
@@ -56,10 +65,11 @@ public function setUp()
->disableOriginalConstructor()
->getMock();
- $this->command = new ApplicationDumpCommand($this->writer, [[
- 'namespace' => 'system',
- 'source' => $this->source
- ]]);
+ $this->command = new ApplicationDumpCommand(
+ $this->writer,
+ [['namespace' => 'system', 'source' => $this->source]],
+ $this->configHashMock
+ );
}
public function testExport()
@@ -68,6 +78,8 @@ public function testExport()
'system' => ['systemDATA']
];
$data = [ConfigFilePool::APP_CONFIG => $dump];
+ $this->configHashMock->expects($this->once())
+ ->method('regenerate');
$this->source
->expects($this->once())
->method('get')
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/ConfigWriterTest.php b/app/code/Magento/Deploy/Test/Unit/Model/ConfigWriterTest.php
index 8dfec06a1c2ae..8764502d80744 100644
--- a/app/code/Magento/Deploy/Test/Unit/Model/ConfigWriterTest.php
+++ b/app/code/Magento/Deploy/Test/Unit/Model/ConfigWriterTest.php
@@ -65,7 +65,7 @@ public function testSave()
->willReturn($config);
$this->writerMock->expects($this->once())
->method('saveConfig')
- ->with([ConfigFilePool::APP_CONFIG => $config]);
+ ->with([ConfigFilePool::APP_ENV => $config]);
$this->model->save($values, 'scope', 'scope_code');
}
@@ -89,7 +89,7 @@ public function testSaveDefaultScope()
->willReturn($config);
$this->writerMock->expects($this->once())
->method('saveConfig')
- ->with([ConfigFilePool::APP_CONFIG => $config]);
+ ->with([ConfigFilePool::APP_ENV => $config]);
$this->model->save($values);
}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/DataCollectorTest.php b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/DataCollectorTest.php
new file mode 100644
index 0000000000000..484c7c6407a85
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/DataCollectorTest.php
@@ -0,0 +1,59 @@
+configImporterPoolMock = $this->getMockBuilder(ImporterPool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->dataCollector = new DataCollector($this->configImporterPoolMock, $this->deploymentConfigMock);
+ }
+
+ /**
+ * @return void
+ */
+ public function testGetConfig()
+ {
+ $sections = ['first', 'second'];
+ $this->configImporterPoolMock->expects($this->once())
+ ->method('getSections')
+ ->willReturn($sections);
+ $this->deploymentConfigMock->expects($this->any())
+ ->method('getConfigData')
+ ->willReturnMap([['first', 'some data']]);
+
+ $this->assertSame(['first' => 'some data'], $this->dataCollector->getConfig());
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/Hash/GeneratorTest.php b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/Hash/GeneratorTest.php
new file mode 100644
index 0000000000000..350426825a682
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/Hash/GeneratorTest.php
@@ -0,0 +1,50 @@
+serializerMock = $this->getMockBuilder(SerializerInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->generator = new Generator($this->serializerMock);
+ }
+
+ /**
+ * @return void
+ */
+ public function testGenerate()
+ {
+ $data = 'some config';
+ $serializedData = 'serialized content';
+ $hash = '40c185113eb5154ad9aa5a8854f197c818e17f62';
+
+ $this->serializerMock->expects($this->once())
+ ->method('serialize')
+ ->with($data)
+ ->willReturn($serializedData);
+
+ $this->assertSame($hash, $this->generator->generate($data));
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/HashTest.php b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/HashTest.php
new file mode 100644
index 0000000000000..74956f98aa817
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/HashTest.php
@@ -0,0 +1,133 @@
+deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->writerMock = $this->getMockBuilder(Writer::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->configHashGeneratorMock = $this->getMockBuilder(Generator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->dataConfigCollectorMock = $this->getMockBuilder(DataCollector::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->hash = new Hash(
+ $this->deploymentConfigMock,
+ $this->writerMock,
+ $this->configHashGeneratorMock,
+ $this->dataConfigCollectorMock
+ );
+ }
+
+ /**
+ * @return void
+ */
+ public function testGet()
+ {
+ $result = 'some data';
+ $this->deploymentConfigMock->expects($this->once())
+ ->method('getConfigData')
+ ->with(Hash::CONFIG_KEY)
+ ->willReturn($result);
+
+ $this->assertSame($result, $this->hash->get());
+ }
+
+ /**
+ * @return void
+ */
+ public function testRegenerate()
+ {
+ $config = 'some config';
+ $hash = 'some hash';
+
+ $this->generalRegenerateMocks($config, $hash);
+ $this->writerMock->expects($this->once())
+ ->method('saveConfig')
+ ->with([ConfigFilePool::APP_ENV => [Hash::CONFIG_KEY => $hash]]);
+
+ $this->hash->regenerate();
+ }
+
+ /**
+ * @return void
+ * @expectedException \Magento\Framework\Exception\LocalizedException
+ * @expectedExceptionMessage Hash has not been saved
+ */
+ public function testRegenerateWithException()
+ {
+ $config = 'some config';
+ $hash = 'some hash';
+
+ $this->generalRegenerateMocks($config, $hash);
+ $this->writerMock->expects($this->once())
+ ->method('saveConfig')
+ ->with([ConfigFilePool::APP_ENV => [Hash::CONFIG_KEY => $hash]])
+ ->willThrowException(new FileSystemException(__('Some error')));
+
+ $this->hash->regenerate();
+ }
+
+ /**
+ * @param string $config
+ * @param string $hash
+ * @return void
+ */
+ private function generalRegenerateMocks($config, $hash)
+ {
+ $this->dataConfigCollectorMock->expects($this->once())
+ ->method('getConfig')
+ ->willReturn($config);
+ $this->configHashGeneratorMock->expects($this->once())
+ ->method('generate')
+ ->with($config)
+ ->willReturn($hash);
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/ImporterPoolTest.php b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/ImporterPoolTest.php
new file mode 100644
index 0000000000000..f3dcfdda3e04d
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/ImporterPoolTest.php
@@ -0,0 +1,89 @@
+importerMock = $this->getMockBuilder(ImporterInterface::class)
+ ->getMockForAbstractClass();
+ $this->wrongImporter = new \StdClass();
+ $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class)
+ ->getMockForAbstractClass();
+ $this->objectManagerMock->expects($this->any())
+ ->method('get')
+ ->willReturnMap([
+ ['Magento\Importer\SomeSection', $this->importerMock],
+ ['Magento\Importer\WrongSection', $this->wrongImporter],
+ ]);
+ $this->configImporterPool = new ImporterPool(
+ $this->objectManagerMock,
+ ['someSection' => 'Magento\Importer\SomeSection']
+ );
+ }
+
+ /**
+ * @return void
+ */
+ public function testGetImporters()
+ {
+ $expectedResult = ['someSection' => $this->importerMock];
+ $this->assertSame($expectedResult, $this->configImporterPool->getImporters());
+ }
+
+ /**
+ * @return void
+ * @expectedException \Magento\Framework\Exception\ConfigurationMismatchException
+ * @codingStandardsIgnoreStart
+ * @expectedExceptionMessage wrongSection: Instance of Magento\Framework\App\DeploymentConfig\ImporterInterface is expected, got stdClass instead
+ * @codingStandardsIgnoreEnd
+ */
+ public function testGetImportersWithException()
+ {
+ $this->configImporterPool = new ImporterPool(
+ $this->objectManagerMock,
+ ['wrongSection' => 'Magento\Importer\WrongSection']
+ );
+
+ $this->configImporterPool->getImporters();
+ }
+
+ /**
+ * @return void
+ */
+ public function testGetSections()
+ {
+ $this->assertSame(['someSection'], $this->configImporterPool->getSections());
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/ValidatorTest.php b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/ValidatorTest.php
new file mode 100644
index 0000000000000..616d2da9291b9
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/DeploymentConfig/ValidatorTest.php
@@ -0,0 +1,94 @@
+configHashMock = $this->getMockBuilder(Hash::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->hashGeneratorMock = $this->getMockBuilder(HashGenerator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->dataConfigCollectorMock = $this->getMockBuilder(DataCollector::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->validator = new Validator(
+ $this->configHashMock,
+ $this->hashGeneratorMock,
+ $this->dataConfigCollectorMock
+ );
+ }
+
+ /**
+ * @param string $configData
+ * @param string $generatedHash
+ * @param string $savedHash
+ * @param bool $expectedResult
+ * @return void
+ * @dataProvider isValidDataProvider
+ */
+ public function testIsValid($configData, $generatedHash, $savedHash, $expectedResult)
+ {
+ $this->dataConfigCollectorMock->expects($this->once())
+ ->method('getConfig')
+ ->willReturn($configData);
+ $this->hashGeneratorMock->expects($this->any())
+ ->method('generate')
+ ->with($configData)
+ ->willReturn($generatedHash);
+ $this->configHashMock->expects($this->any())
+ ->method('get')
+ ->willReturn($savedHash);
+
+ $this->assertSame($expectedResult, $this->validator->isValid());
+ }
+
+ /**
+ * @return array
+ */
+ public function isValidDataProvider()
+ {
+ return [
+ ['configData' => 'some data', 'generatedHash' => '123', 'savedHash' => '123', 'expectedResult' => true],
+ ['configData' => 'some data', 'generatedHash' => '321', 'savedHash' => '123', 'expectedResult' => false],
+ ['configData' => 'some data', 'generatedHash' => '321', 'savedHash' => null, 'expectedResult' => false],
+ ['configData' => null, 'generatedHash' => '321', 'savedHash' => '123', 'expectedResult' => true],
+ ['configData' => null, 'generatedHash' => '321', 'savedHash' => null, 'expectedResult' => true],
+ ];
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php b/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php
new file mode 100644
index 0000000000000..4625e12ee1eca
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php
@@ -0,0 +1,99 @@
+inputMock = $this->getMockBuilder(InputInterface::class)
+ ->getMockForAbstractClass();
+ $this->outputMock = $this->getMockBuilder(OutputInterface::class)
+ ->getMockForAbstractClass();
+ $this->writerMock = $this->getMockBuilder(Writer::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->readerMock = $this->getMockBuilder(Reader::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->maintenanceMock = $this->getMockBuilder(MaintenanceMode::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->filesystemMock = $this->getMockBuilder(Filesystem::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->model = new Mode(
+ $this->inputMock,
+ $this->outputMock,
+ $this->writerMock,
+ $this->readerMock,
+ $this->maintenanceMock,
+ $this->filesystemMock
+ );
+ }
+
+ public function testGetMode()
+ {
+ $this->readerMock->expects($this->exactly(2))
+ ->method('load')
+ ->willReturnOnConsecutiveCalls(
+ [],
+ [State::PARAM_MODE => State::MODE_DEVELOPER]
+ );
+
+ $this->assertSame(null, $this->model->getMode());
+ $this->assertSame(State::MODE_DEVELOPER, $this->model->getMode());
+ }
+}
diff --git a/app/code/Magento/Deploy/Test/Unit/Model/Plugin/ConfigValidatorTest.php b/app/code/Magento/Deploy/Test/Unit/Model/Plugin/ConfigValidatorTest.php
new file mode 100644
index 0000000000000..5121f373dec8c
--- /dev/null
+++ b/app/code/Magento/Deploy/Test/Unit/Model/Plugin/ConfigValidatorTest.php
@@ -0,0 +1,77 @@
+configValidatorMock = $this->getMockBuilder(Validator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->frontControllerMock = $this->getMockBuilder(FrontController::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->requestMock = $this->getMockBuilder(RequestInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->configValidatorPlugin = new ConfigValidator($this->configValidatorMock);
+ }
+
+ /**
+ * @return void
+ */
+ public function testBeforeDispatchWithoutException()
+ {
+ $this->configValidatorMock->expects($this->once())
+ ->method('isValid')
+ ->willReturn(true);
+ $this->configValidatorPlugin->beforeDispatch($this->frontControllerMock, $this->requestMock);
+ }
+
+ /**
+ * @return void
+ * @expectedException \Magento\Framework\Exception\LocalizedException
+ * @codingStandardsIgnoreStart
+ * @expectedExceptionMessage A change in configuration has been detected. Run app:config:import or setup:upgrade command to synchronize configuration.
+ * @codingStandardsIgnoreEnd
+ */
+ public function testBeforeDispatchWithException()
+ {
+ $this->configValidatorMock->expects($this->once())
+ ->method('isValid')
+ ->willReturn(false);
+ $this->configValidatorPlugin->beforeDispatch($this->frontControllerMock, $this->requestMock);
+ }
+}
diff --git a/app/code/Magento/Deploy/etc/di.xml b/app/code/Magento/Deploy/etc/di.xml
index 6751dd1e0b161..86d6ce1da1c75 100644
--- a/app/code/Magento/Deploy/etc/di.xml
+++ b/app/code/Magento/Deploy/etc/di.xml
@@ -20,6 +20,9 @@
+
+
+
@@ -27,6 +30,7 @@
- Magento\Deploy\Console\Command\ShowModeCommand
- \Magento\Deploy\Console\Command\App\ApplicationDumpCommand
- \Magento\Deploy\Console\Command\App\SensitiveConfigSetCommand
+ - Magento\Deploy\Console\Command\App\ConfigImportCommand
diff --git a/app/code/Magento/User/Block/User/Edit/Tab/Main.php b/app/code/Magento/User/Block/User/Edit/Tab/Main.php
index b4a2e2d02d6f7..0e44909ad13a6 100644
--- a/app/code/Magento/User/Block/User/Edit/Tab/Main.php
+++ b/app/code/Magento/User/Block/User/Edit/Tab/Main.php
@@ -8,6 +8,9 @@
namespace Magento\User\Block\User\Edit\Tab;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Locale\OptionInterface;
+
/**
* Cms page edit form main tab
*
@@ -27,6 +30,13 @@ class Main extends \Magento\Backend\Block\Widget\Form\Generic
*/
protected $_LocaleLists;
+ /**
+ * Operates with deployed locales.
+ *
+ * @var OptionInterface
+ */
+ private $deployedLocales;
+
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
@@ -34,6 +44,7 @@ class Main extends \Magento\Backend\Block\Widget\Form\Generic
* @param \Magento\Backend\Model\Auth\Session $authSession
* @param \Magento\Framework\Locale\ListsInterface $localeLists
* @param array $data
+ * @param OptionInterface $deployedLocales Operates with deployed locales.
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
@@ -41,10 +52,13 @@ public function __construct(
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Backend\Model\Auth\Session $authSession,
\Magento\Framework\Locale\ListsInterface $localeLists,
- array $data = []
+ array $data = [],
+ OptionInterface $deployedLocales = null
) {
$this->_authSession = $authSession;
$this->_LocaleLists = $localeLists;
+ $this->deployedLocales = $deployedLocales
+ ?: ObjectManager::getInstance()->get(OptionInterface::class);
parent::__construct($context, $registry, $formFactory, $data);
}
@@ -138,7 +152,7 @@ protected function _prepareForm()
'name' => 'interface_locale',
'label' => __('Interface Locale'),
'title' => __('Interface Locale'),
- 'values' => $this->_LocaleLists->getTranslatedOptionLocales(),
+ 'values' => $this->deployedLocales->getOptionLocales(),
'class' => 'select'
]
);
diff --git a/app/etc/di.xml b/app/etc/di.xml
index ac08fe64fc34b..feac363ee013f 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -34,6 +34,8 @@
+
+
diff --git a/dev/tests/functional/.htaccess.sample b/dev/tests/functional/.htaccess.sample
index 260b8590125d5..d089eb3c4f848 100644
--- a/dev/tests/functional/.htaccess.sample
+++ b/dev/tests/functional/.htaccess.sample
@@ -1,6 +1,6 @@
##############################################
-## Allow access to command.php, website.php, export.php, pathChecker.php, deleteMagentoGeneratedCode.php and log.php
-
+## Allow access to command.php, website.php, export.php, pathChecker.php, locales.php, deleteMagentoGeneratedCode.php and log.php
+
order allow,deny
allow from all
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php
new file mode 100644
index 0000000000000..5f91e36101059
--- /dev/null
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php
@@ -0,0 +1,62 @@
+transport = $transport;
+ }
+
+ /**
+ * Returns array of locales depends on fetching type.
+ *
+ * @param string $type locales fetching type
+ * @return array of locale codes, for example: ['en_US', 'fr_FR']
+ */
+ public function getList($type = self::TYPE_ALL)
+ {
+ $url = $_ENV['app_frontend_url'] . self::URL . '?type=' . $type;
+ $curl = $this->transport;
+ $curl->write($url, [], CurlInterface::GET);
+ $result = $curl->read();
+ $curl->close();
+
+ return explode('|', $result);
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php
new file mode 100644
index 0000000000000..1dde804ca59fe
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php
@@ -0,0 +1,51 @@
+getList(Locales::TYPE_DEPLOYED),
+ $dropdownLocales
+ );
+ } else {
+ \PHPUnit_Framework_Assert::assertEmpty(
+ array_diff($dropdownLocales, $locales->getList(Locales::TYPE_ALL))
+ );
+ }
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return 'Interface locales list has correct values.';
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemAccount.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemAccount.xml
new file mode 100644
index 0000000000000..5a0df9e2a77f7
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemAccount.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/VerifyInterfaceLocaleTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/VerifyInterfaceLocaleTest.php
new file mode 100644
index 0000000000000..b52a1d8c25a64
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/VerifyInterfaceLocaleTest.php
@@ -0,0 +1,85 @@
+systemAccountPage = $systemAccountPage;
+ $this->userEditPage = $userEdit;
+ }
+
+ /**
+ * Test execution.
+ *
+ * @param AssertInterfaceLocaleAvailableOptions $assertInterfaceLocaleAvailableOptions assert that check
+ * interface locales
+ * @param Locales $locales utility for work with locales
+ */
+ public function test(
+ AssertInterfaceLocaleAvailableOptions $assertInterfaceLocaleAvailableOptions,
+ Locales $locales
+ ) {
+ $this->systemAccountPage->open();
+ $userForm = $this->systemAccountPage->getForm();
+ $assertInterfaceLocaleAvailableOptions->processAssert(
+ $locales,
+ $userForm->getInterfaceLocales()
+ );
+
+ $this->userEditPage->open();
+ $userForm = $this->userEditPage->getUserForm();
+ $assertInterfaceLocaleAvailableOptions->processAssert(
+ $locales,
+ $userForm->getInterfaceLocales()
+ );
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/VerifyInterfaceLocaleTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/VerifyInterfaceLocaleTest.xml
new file mode 100644
index 0000000000000..c0276b1237dc9
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/VerifyInterfaceLocaleTest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ severity:S1
+
+
+
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/User/UserForm.php b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/User/UserForm.php
index 89f857823ab2a..f361b693a52e0 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/User/UserForm.php
+++ b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/User/UserForm.php
@@ -3,16 +3,35 @@
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-
namespace Magento\User\Test\Block\Adminhtml\User;
use Magento\Backend\Test\Block\Widget\FormTabs;
/**
- * Class Edit
* User edit form page
*/
class UserForm extends FormTabs
{
- //
+ /**
+ * Interface Locale drop-down selector.
+ *
+ * @var string
+ */
+ private $interfaceLocaleSelect = 'select[name=interface_locale]';
+
+ /**
+ * Gets list of locale codes from "Interface Locale" field.
+ *
+ * @return array of locale codes for example ['en_US', 'de_DE']
+ */
+ public function getInterfaceLocales()
+ {
+ $locales = [];
+ $selectElement = $this->_rootElement->find($this->interfaceLocaleSelect);
+ foreach ($selectElement->getElements('option') as $option) {
+ $locales[] = $option->getValue();
+ }
+
+ return $locales;
+ }
}
diff --git a/dev/tests/functional/utils/locales.php b/dev/tests/functional/utils/locales.php
new file mode 100644
index 0000000000000..b3909dc522104
--- /dev/null
+++ b/dev/tests/functional/utils/locales.php
@@ -0,0 +1,17 @@
+create(\Magento\Framework\Locale\Config::class);
+ $locales = $localeConfig->getAllowedLocales();
+}
+
+echo implode('|', $locales);
diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php
index 724c379cc9511..2570c2b6c92e5 100644
--- a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php
+++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php
@@ -5,21 +5,23 @@
*/
namespace Magento\Config\Console\Command;
+use Magento\Config\Model\Config\PathValidator;
+use Magento\Config\Model\Config\PathValidatorFactory;
use Magento\Framework\App\Config\ConfigPathResolver;
use Magento\Framework\App\Config\ScopeConfigInterface;
-use Magento\Framework\App\DeploymentConfig\Reader;
+use Magento\Framework\App\DeploymentConfig\FileReader;
use Magento\Framework\App\DeploymentConfig\Writer;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Config\File\ConfigFilePool;
use Magento\Framework\Console\Cli;
+use Magento\Framework\Filesystem;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Stdlib\ArrayManager;
use Magento\Store\Model\ScopeInterface;
use Magento\TestFramework\Helper\Bootstrap;
+use PHPUnit_Framework_MockObject_MockObject as Mock;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Magento\Framework\Filesystem;
-use PHPUnit_Framework_MockObject_MockObject as Mock;
/**
* Tests the different flows of config:set command.
@@ -44,13 +46,23 @@ class ConfigSetCommandTest extends \PHPUnit_Framework_TestCase
*/
private $outputMock;
+ /**
+ * @var PathValidatorFactory|Mock
+ */
+ private $pathValidatorFactoryMock;
+
+ /**
+ * @var PathValidator|Mock
+ */
+ private $pathValidatorMock;
+
/**
* @var ScopeConfigInterface
*/
private $scopeConfig;
/**
- * @var Reader
+ * @var FileReader
*/
private $reader;
@@ -81,7 +93,7 @@ protected function setUp()
{
$this->objectManager = Bootstrap::getObjectManager();
$this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class);
- $this->reader = $this->objectManager->get(Reader::class);
+ $this->reader = $this->objectManager->get(FileReader::class);
$this->filesystem = $this->objectManager->get(Filesystem::class);
$this->configFilePool = $this->objectManager->get(ConfigFilePool::class);
$this->arrayManager = $this->objectManager->get(ArrayManager::class);
@@ -94,6 +106,18 @@ protected function setUp()
->getMockForAbstractClass();
$this->outputMock = $this->getMockBuilder(OutputInterface::class)
->getMockForAbstractClass();
+ $this->pathValidatorFactoryMock = $this->getMockBuilder(PathValidatorFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->pathValidatorMock = $this->getMockBuilder(PathValidator::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['validate'])
+ ->getMock();
+
+ $this->pathValidatorFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($this->pathValidatorMock);
}
/**
@@ -102,12 +126,12 @@ protected function setUp()
protected function tearDown()
{
$this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
- $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
+ $this->configFilePool->getPath(ConfigFilePool::APP_ENV),
"objectManager->get(Writer::class);
- $writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]);
+ $writer->saveConfig([ConfigFilePool::APP_ENV => $this->config]);
}
/**
@@ -115,11 +139,7 @@ protected function tearDown()
*/
private function loadConfig()
{
- return $this->reader->loadConfigFile(
- ConfigFilePool::APP_CONFIG,
- $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
- true
- );
+ return $this->reader->load(ConfigFilePool::APP_ENV);
}
/**
@@ -155,7 +175,9 @@ public function testRun($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE
);
/** @var ConfigSetCommand $command */
- $command = $this->objectManager->create(ConfigSetCommand::class);
+ $command = $this->objectManager->create(ConfigSetCommand::class, [
+ 'pathValidatorFactory' => $this->pathValidatorFactoryMock,
+ ]);
$status = $command->run($this->inputMock, $this->outputMock);
$this->assertSame(Cli::RETURN_SUCCESS, $status);
@@ -212,7 +234,9 @@ public function testRunLock($path, $value, $scope = ScopeConfigInterface::SCOPE_
);
/** @var ConfigSetCommand $command */
- $command = $this->objectManager->create(ConfigSetCommand::class);
+ $command = $this->objectManager->create(ConfigSetCommand::class, [
+ 'pathValidatorFactory' => $this->pathValidatorFactoryMock,
+ ]);
/** @var ConfigPathResolver $resolver */
$resolver = $this->objectManager->get(ConfigPathResolver::class);
$status = $command->run($this->inputMock, $this->outputMock);
@@ -310,7 +334,9 @@ private function runCommand(
->with($expectedMessage);
/** @var ConfigSetCommand $command */
- $command = $this->objectManager->create(ConfigSetCommand::class);
+ $command = $this->objectManager->create(ConfigSetCommand::class, [
+ 'pathValidatorFactory' => $this->pathValidatorFactoryMock,
+ ]);
$status = $command->run($input, $output);
$this->assertSame($expectedCode, $status);
@@ -360,7 +386,9 @@ public function testRunScopeValidation(
$expectations($this->outputMock);
/** @var ConfigSetCommand $command */
- $command = $this->objectManager->create(ConfigSetCommand::class);
+ $command = $this->objectManager->create(ConfigSetCommand::class, [
+ 'pathValidatorFactory' => $this->pathValidatorFactoryMock,
+ ]);
$command->run($this->inputMock, $this->outputMock);
}
@@ -418,4 +446,82 @@ function (Mock $output) {
]
];
}
+
+ /**
+ * Tests different scenarios for scope options.
+ *
+ * @param \Closure $expectations
+ * @param string $path
+ * @param string $value
+ * @param string $scope
+ * @param string $scopeCode
+ * @magentoDbIsolation enabled
+ * @dataProvider getRunPathValidationDataProvider
+ */
+ public function testRunPathValidation(
+ \Closure $expectations,
+ $path,
+ $value,
+ $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
+ $scopeCode = null
+ ) {
+ $this->inputMock->expects($this->any())
+ ->method('getArgument')
+ ->willReturnMap([
+ [ConfigSetCommand::ARG_PATH, $path],
+ [ConfigSetCommand::ARG_VALUE, $value]
+ ]);
+ $this->inputMock->expects($this->any())
+ ->method('getOption')
+ ->willReturnMap([
+ [ConfigSetCommand::OPTION_SCOPE, $scope],
+ [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode]
+ ]);
+
+ $expectations($this->outputMock);
+
+ /** @var ConfigSetCommand $command */
+ $command = $this->objectManager->create(ConfigSetCommand::class);
+ $command->run($this->inputMock, $this->outputMock);
+ }
+
+ /**
+ * Retrieves variations with callback, path, value, scope and scope code.
+ *
+ * @return array
+ */
+ public function getRunPathValidationDataProvider()
+ {
+ return [
+ [
+ function (Mock $output) {
+ $output->expects($this->once())
+ ->method('writeln')
+ ->with('Value was saved.');
+ },
+ 'web/unsecure/base_url',
+ 'http://magento2.local/',
+ ],
+ [
+ function (Mock $output) {
+ $output->expects($this->once())
+ ->method('writeln')
+ ->with(
+ 'Invalid Base URL. Value must be a URL or one of placeholders: {{base_url}}'
+ );
+ },
+ 'web/unsecure/base_url',
+ 'value',
+ ],
+ [
+ function (Mock $output) {
+ $output->expects($this->once())
+ ->method('writeln')
+ ->with('The "test/test/test" path does not exist');
+ },
+ 'test/test/test',
+ 'value',
+ ]
+ ];
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php
index 596729fc107ac..658a9148f765b 100644
--- a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php
+++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Config\Console\Command;
+use Magento\Framework\App\DeploymentConfig\FileReader;
use Magento\Store\Model\ScopeInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\Framework\Console\Cli;
@@ -13,7 +14,6 @@
use Magento\Framework\Filesystem;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Config\File\ConfigFilePool;
-use Magento\Framework\App\DeploymentConfig\Reader;
use Magento\Framework\App\DeploymentConfig\Writer;
class ConfigShowCommandTest extends \PHPUnit_Framework_TestCase
@@ -39,7 +39,7 @@ class ConfigShowCommandTest extends \PHPUnit_Framework_TestCase
private $configFilePool;
/**
- * @var Reader
+ * @var FileReader
*/
private $reader;
@@ -58,25 +58,32 @@ class ConfigShowCommandTest extends \PHPUnit_Framework_TestCase
*/
private $config;
+ /**
+ * @var array
+ */
+ private $envConfig;
+
+ /**
+ * @inheritdoc
+ */
public function setUp()
{
$this->objectManager = Bootstrap::getObjectManager();
$this->configFilePool = $this->objectManager->get(ConfigFilePool::class);
$this->filesystem = $this->objectManager->get(Filesystem::class);
- $this->reader = $this->objectManager->get(Reader::class);
+ $this->reader = $this->objectManager->get(FileReader::class);
$this->writer = $this->objectManager->get(Writer::class);
$this->config = $this->loadConfig();
+ $this->envConfig = $this->loadEnvConfig();
$this->env = $_ENV;
- $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
- $this->getFileName(),
- file_get_contents(__DIR__ . '/../../_files/_config.local.php')
- );
-
- $config = include(__DIR__ . '/../../_files/_config.php');
+ $config = include(__DIR__ . '/../../_files/config.php');
$this->writer->saveConfig([ConfigFilePool::APP_CONFIG => $config]);
+ $config = include(__DIR__ . '/../../_files/env.php');
+ $this->writer->saveConfig([ConfigFilePool::APP_ENV => $config]);
+
$_ENV['CONFIG__DEFAULT__WEB__TEST2__TEST_VALUE_4'] = 'value4.env.default.test';
$_ENV['CONFIG__WEBSITES__BASE__WEB__TEST2__TEST_VALUE_4'] = 'value4.env.website_base.test';
$_ENV['CONFIG__STORES__DEFAULT__WEB__TEST2__TEST_VALUE_4'] = 'value4.env.store_default.test';
@@ -138,6 +145,7 @@ public function executeDataProvider()
'web/test/test_value_2' => ['value2.local_config.default.test'],
'web/test2/test_value_3' => ['value3.config.default.test'],
'web/test2/test_value_4' => ['value4.env.default.test'],
+ 'carriers/fedex/account' => ['******'],
'web/test' => [
'web/test/test_value_1 - value1.db.default.test',
'web/test/test_value_2 - value2.local_config.default.test',
@@ -157,6 +165,7 @@ public function executeDataProvider()
'web/test/test_value_2 - value2.local_config.default.test',
'web/test2/test_value_3 - value3.config.default.test',
'web/test2/test_value_4 - value4.env.default.test',
+ 'carriers/fedex/account - ******',
],
]
],
@@ -276,37 +285,35 @@ public function executeDataProvider()
}
/**
- * @return string
+ * @return array
*/
- private function getFileName()
+ private function loadConfig()
{
- $filePool = $this->configFilePool->getInitialFilePools();
-
- return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG];
+ return $this->reader->load(ConfigFilePool::APP_CONFIG);
}
/**
* @return array
*/
- private function loadConfig()
+ private function loadEnvConfig()
{
- return $this->reader->loadConfigFile(
- ConfigFilePool::APP_CONFIG,
- $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
- true
- );
+ return $this->reader->load(ConfigFilePool::APP_ENV);
}
public function tearDown()
{
$_ENV = $this->env;
- $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->delete(
- $this->getFileName()
- );
+
$this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
$this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
"filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_ENV),
+ "writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]);
+ $this->writer->saveConfig([ConfigFilePool::APP_ENV => $this->envConfig]);
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Config/_files/_config.local.php b/dev/tests/integration/testsuite/Magento/Config/_files/config.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Config/_files/_config.local.php
rename to dev/tests/integration/testsuite/Magento/Config/_files/config.php
diff --git a/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php b/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php
index 9b9c2fe6c826a..f48a932a70009 100644
--- a/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php
+++ b/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php
@@ -16,6 +16,7 @@
'web/test/test_value_2' => 'value2.db.default.test',
'web/test2/test_value_3' => 'value3.db.default.test',
'web/test2/test_value_4' => 'value4.db.default.test',
+ 'carriers/fedex/account' => 'value5.db.hashed.value',
]
],
ScopeInterface::SCOPE_WEBSITES => [
diff --git a/dev/tests/integration/testsuite/Magento/Config/_files/_config.php b/dev/tests/integration/testsuite/Magento/Config/_files/env.php
similarity index 56%
rename from dev/tests/integration/testsuite/Magento/Config/_files/_config.php
rename to dev/tests/integration/testsuite/Magento/Config/_files/env.php
index 79eb6e7e12db8..99285e9344df5 100644
--- a/dev/tests/integration/testsuite/Magento/Config/_files/_config.php
+++ b/dev/tests/integration/testsuite/Magento/Config/_files/env.php
@@ -4,6 +4,40 @@
* See COPYING.txt for license details.
*/
return [
+ 'backend' => [
+ 'frontName' => 'admin',
+ ],
+ 'crypt' => [
+ 'key' => 'some_key',
+ ],
+ 'session' => [
+ 'save' => 'files',
+ ],
+ 'db' => [
+ 'table_prefix' => '',
+ 'connection' => [],
+ ],
+ 'resource' => [],
+ 'x-frame-options' => 'SAMEORIGIN',
+ 'MAGE_MODE' => 'default',
+ 'cache_types' => [
+ 'config' => 1,
+ 'layout' => 1,
+ 'block_html' => 1,
+ 'collections' => 1,
+ 'reflection' => 1,
+ 'db_ddl' => 1,
+ 'eav' => 1,
+ 'customer_notification' => 1,
+ 'config_integration' => 1,
+ 'config_integration_api' => 1,
+ 'full_page' => 1,
+ 'translate' => 1,
+ 'config_webservice' => 1,
+ ],
+ 'install' => [
+ 'date' => 'Thu, 09 Feb 2017 14:28:00 +0000',
+ ],
'system' => [
'default' => [
'web' => [
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php
index 8d8c16bf3be83..7b32104ca8521 100644
--- a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php
+++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php
@@ -5,15 +5,19 @@
*/
namespace Magento\Deploy\Console\Command\App;
+use Magento\Deploy\Model\DeploymentConfig\Hash;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Config\File\ConfigFilePool;
-use Magento\Framework\Filesystem\DriverPool;
+use Magento\Framework\Filesystem;
use Magento\Framework\ObjectManagerInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase
{
/**
@@ -22,14 +26,67 @@ class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase
private $objectManager;
/**
- * @var DeploymentConfig\Reader
+ * @var DeploymentConfig\FileReader
*/
private $reader;
+ /**
+ * @var ConfigFilePool
+ */
+ private $configFilePool;
+
+ /**
+ * @var Filesystem
+ */
+ private $filesystem;
+
+ /**
+ * @var DeploymentConfig\Writer
+ */
+ private $writer;
+
+ /**
+ * @var array
+ */
+ private $config;
+
+ /**
+ * @var array
+ */
+ private $envConfig;
+
+ /**
+ * @inheritdoc
+ */
public function setUp()
{
$this->objectManager = Bootstrap::getObjectManager();
+ $this->reader = $this->objectManager->get(DeploymentConfig\FileReader::class);
+ $this->filesystem = $this->objectManager->get(Filesystem::class);
+ $this->configFilePool = $this->objectManager->get(ConfigFilePool::class);
$this->reader = $this->objectManager->get(DeploymentConfig\Reader::class);
+ $this->writer = $this->objectManager->get(DeploymentConfig\Writer::class);
+ $this->configFilePool = $this->objectManager->get(ConfigFilePool::class);
+
+ // Snapshot of configuration.
+ $this->config = $this->loadConfig();
+ $this->envConfig = $this->loadEnvConfig();
+ }
+
+ /**
+ * @return array
+ */
+ private function loadConfig()
+ {
+ return $this->reader->load(ConfigFilePool::APP_CONFIG);
+ }
+
+ /**
+ * @return array
+ */
+ private function loadEnvConfig()
+ {
+ return $this->reader->load(ConfigFilePool::APP_ENV);
}
/**
@@ -38,6 +95,7 @@ public function setUp()
*/
public function testExecute()
{
+ $this->assertArrayNotHasKey(Hash::CONFIG_KEY, $this->envConfig);
$this->objectManager->configure([
\Magento\Config\Model\Config\Export\ExcludeList::class => [
'arguments' => [
@@ -65,10 +123,11 @@ public function testExecute()
$command = $this->objectManager->create(ApplicationDumpCommand::class);
$command->run($this->getMock(InputInterface::class), $outputMock);
- $config = $this->reader->loadConfigFile(ConfigFilePool::APP_CONFIG, $this->getFileName());
+ $config = $this->loadConfig();
$this->validateSystemSection($config);
$this->validateThemesSection($config);
+ $this->assertArrayHasKey(Hash::CONFIG_KEY, $this->loadEnvConfig());
}
/**
@@ -139,31 +198,27 @@ private function validateThemesSection(array $config)
);
}
+ /**
+ * @inheritdoc
+ */
public function tearDown()
{
- $file = $this->getFileName();
- /** @var DirectoryList $dirList */
- $dirList = $this->objectManager->get(DirectoryList::class);
- $path = $dirList->getPath(DirectoryList::CONFIG);
- $driverPool = $this->objectManager->get(DriverPool::class);
- $fileDriver = $driverPool->getDriver(DriverPool::FILE);
- if ($fileDriver->isExists($path . '/' . $file)) {
- unlink($path . '/' . $file);
- }
+ $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
+ "objectManager->get(DeploymentConfig\Writer::class);
+ $writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]);
+
/** @var DeploymentConfig $deploymentConfig */
$deploymentConfig = $this->objectManager->get(DeploymentConfig::class);
$deploymentConfig->resetData();
- }
- /**
- * @return string
- */
- private function getFileName()
- {
- /** @var ConfigFilePool $configFilePool */
- $configFilePool = $this->objectManager->get(ConfigFilePool::class);
- $filePool = $configFilePool->getInitialFilePools();
-
- return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG];
+ $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_ENV),
+ "writer->saveConfig([ConfigFilePool::APP_ENV => $this->envConfig]);
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ConfigImportCommand/IntegrationTestImporter.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ConfigImportCommand/IntegrationTestImporter.php
new file mode 100644
index 0000000000000..131be392d00c9
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ConfigImportCommand/IntegrationTestImporter.php
@@ -0,0 +1,22 @@
+Integration test data is imported!';
+
+ return $messages;
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ConfigImportCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ConfigImportCommandTest.php
new file mode 100644
index 0000000000000..6c32edee01200
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ConfigImportCommandTest.php
@@ -0,0 +1,142 @@
+objectManager = Bootstrap::getObjectManager();
+ $this->objectManager->configure([
+ ImporterPool::class => [
+ 'arguments' => [
+ 'importers' => [
+ 'integrationTestImporter' => IntegrationTestImporter::class
+ ]
+ ]
+ ]
+ ]);
+ $this->reader = $this->objectManager->get(DeploymentConfig\Reader::class);
+ $this->writer = $this->objectManager->get(DeploymentConfig\Writer::class);
+ $this->filesystem = $this->objectManager->get(Filesystem::class);
+ $this->configFilePool = $this->objectManager->get(ConfigFilePool::class);
+
+ $this->envConfig = $this->loadEnvConfig();
+ $this->config = $this->loadConfig();
+ }
+
+ public function tearDown()
+ {
+ $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
+ "objectManager->get(DeploymentConfig\Writer::class);
+ $writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]);
+
+ $this->filesystem = $this->objectManager->get(Filesystem::class);
+ $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_ENV),
+ "writer->saveConfig([ConfigFilePool::APP_ENV => $this->envConfig]);
+ }
+
+ public function testExecuteNothingImport()
+ {
+ $this->assertArrayNotHasKey(Hash::CONFIG_KEY, $this->envConfig);
+ $command = $this->objectManager->create(ConfigImportCommand::class);
+ $commandTester = new CommandTester($command);
+ $commandTester->execute([]);
+ $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->getStatusCode());
+ $this->assertContains('Start import', $commandTester->getDisplay());
+ $this->assertContains('Nothing to import', $commandTester->getDisplay());
+ $this->assertArrayNotHasKey(Hash::CONFIG_KEY, $this->loadEnvConfig());
+ }
+
+ public function testExecuteWithImport()
+ {
+ $this->assertArrayNotHasKey(Hash::CONFIG_KEY, $this->envConfig);
+ $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
+ file_get_contents(__DIR__ . '/../../../_files/config.php')
+ );
+ $command = $this->objectManager->create(ConfigImportCommand::class);
+ $commandTester = new CommandTester($command);
+ $commandTester->execute([]);
+ $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->getStatusCode());
+ $this->assertContains('Start import', $commandTester->getDisplay());
+ $this->assertContains('Integration test data is imported!', $commandTester->getDisplay());
+ $this->assertArrayHasKey(Hash::CONFIG_KEY, $this->loadEnvConfig());
+ }
+
+ /**
+ * @return array
+ */
+ private function loadConfig()
+ {
+ return $this->reader->load(ConfigFilePool::APP_CONFIG);
+ }
+
+ /**
+ * @return array
+ */
+ private function loadEnvConfig()
+ {
+ return $this->reader->load(ConfigFilePool::APP_ENV);
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php
index ad51c02eaeda6..c2ea062de0543 100644
--- a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php
+++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php
@@ -8,7 +8,7 @@
use Magento\Deploy\Console\Command\App\SensitiveConfigSet\CollectorFactory;
use Magento\Deploy\Console\Command\App\SensitiveConfigSet\InteractiveCollector;
use Magento\Framework\App\Config\ScopeConfigInterface;
-use Magento\Framework\App\DeploymentConfig\Reader;
+use Magento\Framework\App\DeploymentConfig\FileReader;
use Magento\Framework\App\DeploymentConfig\Writer;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Config\File\ConfigFilePool;
@@ -30,15 +30,25 @@ class SensitiveConfigSetCommandTest extends \PHPUnit_Framework_TestCase
private $objectManager;
/**
- * @var Reader
+ * @var FileReader
*/
private $reader;
+ /**
+ * @var Writer
+ */
+ private $writer;
+
/**
* @var ConfigFilePool
*/
private $configFilePool;
+ /**
+ * @var array
+ */
+ private $envConfig;
+
/**
* @var array
*/
@@ -55,13 +65,17 @@ class SensitiveConfigSetCommandTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
$this->objectManager = Bootstrap::getObjectManager();
- $this->reader = $this->objectManager->get(Reader::class);
+ $this->reader = $this->objectManager->get(FileReader::class);
+ $this->writer = $this->objectManager->get(Writer::class);
$this->configFilePool = $this->objectManager->get(ConfigFilePool::class);
- $this->config = $this->loadConfig();
$this->filesystem = $this->objectManager->get(Filesystem::class);
+
+ $this->envConfig = $this->loadEnvConfig();
+ $this->config = $this->loadConfig();
+
$this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
- $this->getFileName(),
- file_get_contents(__DIR__ . '/../../../_files/_config.local.php')
+ $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
+ file_get_contents(__DIR__ . '/../../../_files/config.php')
);
}
@@ -71,14 +85,14 @@ public function setUp()
* @param callable $assertCallback
* @magentoDataFixture Magento/Store/_files/website.php
* @magentoDbIsolation enabled
- * @dataProvider testExecuteDataProvider
+ * @dataProvider executeDataProvider
*/
public function testExecute($scope, $scopeCode, callable $assertCallback)
{
$outputMock = $this->getMock(OutputInterface::class);
$outputMock->expects($this->at(0))
->method('writeln')
- ->with('Configuration value saved in app/etc/config.php');
+ ->with('Configuration value saved in app/etc/env.php');
$inputMock = $this->getMock(InputInterface::class);
$inputMock->expects($this->exactly(2))
@@ -108,12 +122,12 @@ public function testExecute($scope, $scopeCode, callable $assertCallback)
$command = $this->objectManager->create(SensitiveConfigSetCommand::class);
$command->run($inputMock, $outputMock);
- $config = $this->loadConfig();
+ $config = $this->loadEnvConfig();
$assertCallback($config);
}
- public function testExecuteDataProvider()
+ public function executeDataProvider()
{
return [
[
@@ -147,7 +161,7 @@ function (array $config) {
* @param callable $assertCallback
* @magentoDataFixture Magento/Store/_files/website.php
* @magentoDbIsolation enabled
- * @dataProvider testExecuteInteractiveDataProvider
+ * @dataProvider executeInteractiveDataProvider
*/
public function testExecuteInteractive($scope, $scopeCode, callable $assertCallback)
{
@@ -158,7 +172,7 @@ public function testExecuteInteractive($scope, $scopeCode, callable $assertCallb
->with('Please set configuration values or skip them by pressing [Enter]:');
$outputMock->expects($this->at(1))
->method('writeln')
- ->with('Configuration values saved in app/etc/config.php');
+ ->with('Configuration values saved in app/etc/env.php');
$inputMock->expects($this->exactly(3))
->method('getOption')
->withConsecutive(
@@ -201,12 +215,12 @@ public function testExecuteInteractive($scope, $scopeCode, callable $assertCallb
);
$command->run($inputMock, $outputMock);
- $config = $this->loadConfig();
+ $config = $this->loadEnvConfig();
$assertCallback($config);
}
- public function testExecuteInteractiveDataProvider()
+ public function executeInteractiveDataProvider()
{
return [
[
@@ -259,28 +273,30 @@ function (array $config) {
*/
public function tearDown()
{
- $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->delete(
- $this->getFileName()
- );
$this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
$this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
"filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile(
+ $this->configFilePool->getPath(ConfigFilePool::APP_ENV),
+ "objectManager->get(Writer::class);
+ $writer->saveConfig([ConfigFilePool::APP_ENV => $this->envConfig]);
+
/** @var Writer $writer */
$writer = $this->objectManager->get(Writer::class);
$writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]);
}
/**
- * @return string
+ * @return array
*/
- private function getFileName()
+ private function loadEnvConfig()
{
- /** @var ConfigFilePool $configFilePool */
- $configFilePool = $this->objectManager->get(ConfigFilePool::class);
- $filePool = $configFilePool->getInitialFilePools();
-
- return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG];
+ return $this->reader->load(ConfigFilePool::APP_ENV);
}
/**
@@ -288,10 +304,6 @@ private function getFileName()
*/
private function loadConfig()
{
- return $this->reader->loadConfigFile(
- ConfigFilePool::APP_CONFIG,
- $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG),
- true
- );
+ return $this->reader->load(ConfigFilePool::APP_CONFIG);
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/_config.local.php b/dev/tests/integration/testsuite/Magento/Deploy/_files/config.php
similarity index 84%
rename from dev/tests/integration/testsuite/Magento/Deploy/_files/_config.local.php
rename to dev/tests/integration/testsuite/Magento/Deploy/_files/config.php
index ae4630b1a2b07..1a392714716c2 100644
--- a/dev/tests/integration/testsuite/Magento/Deploy/_files/_config.local.php
+++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/config.php
@@ -19,5 +19,10 @@
'web' => [],
'general' => []
]
- ]
+ ],
+ 'integrationTestImporter' => [
+ 'someGroup' => [
+ 'someField' => 'testValue',
+ ]
+ ],
];
diff --git a/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php b/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php
index 1c1b3e9272a13..1b018a650b546 100644
--- a/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php
+++ b/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php
@@ -25,6 +25,7 @@ class InitialConfigSource implements ConfigSourceInterface
/**
* @var string
+ * @deprecated Initial configs can not be separated since 2.2.0 version
*/
private $fileKey;
@@ -35,7 +36,7 @@ class InitialConfigSource implements ConfigSourceInterface
* @param string $configType
* @param string $fileKey
*/
- public function __construct(Reader $reader, $configType, $fileKey)
+ public function __construct(Reader $reader, $configType, $fileKey = null)
{
$this->reader = $reader;
$this->configType = $configType;
@@ -47,7 +48,7 @@ public function __construct(Reader $reader, $configType, $fileKey)
*/
public function get($path = '')
{
- $data = new DataObject($this->reader->load($this->fileKey));
+ $data = new DataObject($this->reader->load());
if ($path !== '' && $path !== null) {
$path = '/' . $path;
}
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/FileReader.php b/lib/internal/Magento/Framework/App/DeploymentConfig/FileReader.php
new file mode 100644
index 0000000000000..e38f850999fbb
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/FileReader.php
@@ -0,0 +1,76 @@
+dirList = $dirList;
+ $this->configFilePool = $configFilePool;
+ $this->driverPool = $driverPool;
+ }
+
+ /**
+ * Loads the configuration file.
+ *
+ * @param string $fileKey The file key
+ * @return array The configurations array
+ * @throws FileSystemException If file can not be read
+ * @throws \Exception If file key is not correct
+ */
+ public function load($fileKey)
+ {
+ $path = $this->dirList->getPath(DirectoryList::CONFIG);
+ $fileDriver = $this->driverPool->getDriver(DriverPool::FILE);
+ $filePath = $path . '/' . $this->configFilePool->getPath($fileKey);
+
+ if ($fileDriver->isExists($filePath)) {
+ return include $filePath;
+ }
+
+ return [];
+ }
+}
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/ImporterInterface.php b/lib/internal/Magento/Framework/App/DeploymentConfig/ImporterInterface.php
new file mode 100644
index 0000000000000..81617f00c5b49
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/ImporterInterface.php
@@ -0,0 +1,24 @@
+dirList->getPath(DirectoryList::CONFIG);
- $fileDriver = $this->driverPool->getDriver(DriverPool::FILE);
- $initialFilePools = $this->configFilePool->getInitialFilePools();
-
- $files = [];
- foreach ($this->files as $fileKey => $filePath) {
- $files[$fileKey] = $filePath;
- if (!$fileDriver->isExists($path . "/" . $filePath)) {
- foreach ($initialFilePools as $initialFiles) {
- if (
- isset($initialFiles[$fileKey])
- && $fileDriver->isExists($path . '/' . $initialFiles[$fileKey])
- ) {
- $files[$fileKey] = $initialFiles[$fileKey];
- }
- }
- }
- }
-
- return $files;
+ return $this->files;
}
/**
- * Loads the configuration file
+ * Method loads merged configuration within all configuration files.
+ * To retrieve specific file configuration, use FileReader.
+ * $fileKey option is deprecated since version 2.2.0.
*
- * @param string $fileKey
+ * @param string $fileKey The file key (deprecated)
* @return array
- * @throws \Exception
+ * @throws FileSystemException If file can not be read
+ * @throws \Exception If file key is not correct
+ * @see FileReader
*/
public function load($fileKey = null)
{
+ $path = $this->dirList->getPath(DirectoryList::CONFIG);
+ $fileDriver = $this->driverPool->getDriver(DriverPool::FILE);
+ $result = [];
if ($fileKey) {
- $pathConfig = $this->configFilePool->getPath($fileKey);
- return $this->loadConfigFile($fileKey, $pathConfig);
+ $filePath = $path . '/' . $this->configFilePool->getPath($fileKey);
+ if ($fileDriver->isExists($filePath)) {
+ $result = include $filePath;
+ }
} else {
$configFiles = $this->configFilePool->getPaths();
$allFilesData = [];
$result = [];
- foreach ($configFiles as $fileKey => $pathConfig) {
- $fileData = $this->loadConfigFile($fileKey, $pathConfig);
- if (!$fileData) {
+ foreach (array_keys($configFiles) as $fileKey) {
+ $configFile = $path . '/' . $this->configFilePool->getPath($fileKey);
+ if ($fileDriver->isExists($configFile)) {
+ $fileData = include $configFile;
+ } else {
continue;
}
- $allFilesData[$fileKey] = $fileData;
+ $allFilesData[$configFile] = $fileData;
if (!empty($fileData)) {
- $intersection = array_intersect_key($result, $fileData);
- if (!empty($intersection)) {
- $displayMessage = $this->findFilesWithKeys(array_keys($intersection), $allFilesData);
- throw new \Exception(
- "Key collision! The following keys occur in multiple config files:"
- . PHP_EOL . $displayMessage
- );
- }
- $result = array_merge($result, $fileData);
+ $result = array_replace_recursive($result, $fileData);
}
}
- return $result;
}
+ return $result ?: [];
}
/**
- * @param string $fileKey
- * @param string $pathConfig
- * @param bool $ignoreInitialConfigFiles
+ * Loads the configuration file.
+ *
+ * @param string $fileKey The file key
+ * @param string $pathConfig The path config
+ * @param bool $ignoreInitialConfigFiles Whether ignore custom pools
* @return array
+ * @deprecated Magento does not support custom config file pools since 2.2.0 version
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function loadConfigFile($fileKey, $pathConfig, $ignoreInitialConfigFiles = false)
{
- $result = [];
- $initialFilePools = $this->configFilePool->getInitialFilePools();
- $path = $this->dirList->getPath(DirectoryList::CONFIG);
- $fileDriver = $this->driverPool->getDriver(DriverPool::FILE);
-
- if (!$ignoreInitialConfigFiles) {
- foreach ($initialFilePools as $initialFiles) {
- if (isset($initialFiles[$fileKey]) && $fileDriver->isExists($path . '/' . $initialFiles[$fileKey])) {
- $fileBuffer = include $path . '/' . $initialFiles[$fileKey];
- if (is_array($fileBuffer)) {
- $result = array_replace_recursive($result, $fileBuffer);
- }
- }
- }
- }
-
- if ($fileDriver->isExists($path . '/' . $pathConfig)) {
- $fileBuffer = include $path . '/' . $pathConfig;
- $result = array_replace_recursive($result, $fileBuffer);
- }
-
- if ($fileDriver->isExists($path . '/' . $pathConfig)) {
- $configResult = include $path . '/' . $pathConfig;
- if (is_array($configResult)) {
- $result = array_replace_recursive($result, $configResult);
- }
- }
-
- return $result;
- }
-
- /**
- * Finds list of files that has the key
- *
- * @param array $keys
- * @param array $allFilesData
- * @return string
- */
- private function findFilesWithKeys(array $keys, array $allFilesData)
- {
- $displayMessage = '';
- foreach ($keys as $key) {
- $foundConfigFiles = [];
- foreach ($allFilesData as $fileName => $fileValues) {
- if (isset($fileValues[$key])) {
- $foundConfigFiles[] = $fileName;
- }
- }
- $displayMessage .= 'Key "' . $key . '" found in ' . implode(', ', $foundConfigFiles) . PHP_EOL;
- }
- return $displayMessage;
+ return $this->load($fileKey);
}
}
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php
index badbea2b8b934..2db72e51281b0 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php
@@ -3,18 +3,17 @@
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-
namespace Magento\Framework\App\DeploymentConfig;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Config\File\ConfigFilePool;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Filesystem;
-use Magento\Framework\Config\File\ConfigFilePool;
use Magento\Framework\Phrase;
/**
- * Deployment configuration writer to files: env.php, config.php (config.local.php, config.dist.php)
+ * Deployment configuration writer to files: env.php, config.php.
*/
class Writer
{
@@ -50,8 +49,6 @@ class Writer
private $deploymentConfig;
/**
- * Constructor
- *
* @param Reader $reader
* @param Filesystem $filesystem
* @param ConfigFilePool $configFilePool
@@ -67,9 +64,9 @@ public function __construct(
) {
$this->reader = $reader;
$this->filesystem = $filesystem;
- $this->formatter = $formatter ?: new Writer\PhpFormatter();
$this->configFilePool = $configFilePool;
$this->deploymentConfig = $deploymentConfig;
+ $this->formatter = $formatter ?: new Writer\PhpFormatter();
}
/**
@@ -89,22 +86,36 @@ public function checkIfWritable()
}
/**
- * Saves config
+ * Saves config in specified file.
+ * $pool option is deprecated since version 2.2.0.
+ *
+ * Usage:
+ * ```php
+ * saveConfig(
+ * [
+ * ConfigFilePool::APP_ENV => ['some' => 'value'],
+ * ],
+ * true,
+ * null,
+ * []
+ * )
+ * ```
*
- * @param array $data
- * @param bool $override
- * @param string $pool
- * @param array $comments
+ * @param array $data The data to be saved
+ * @param bool $override Whether values should be overridden
+ * @param string $pool The file pool (deprecated)
+ * @param array $comments The array of comments
* @return void
* @throws FileSystemException
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function saveConfig(array $data, $override = false, $pool = null, array $comments = [])
{
foreach ($data as $fileKey => $config) {
- $paths = $pool ? $this->configFilePool->getPathsByPool($pool) : $this->configFilePool->getPaths();
+ $paths = $this->configFilePool->getPaths();
if (isset($paths[$fileKey])) {
- $currentData = $this->reader->loadConfigFile($fileKey, $paths[$fileKey], true);
+ $currentData = $this->reader->load($fileKey);
if ($currentData) {
if ($override) {
$config = array_merge($currentData, $config);
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php
index cb92ac4ab405a..99fe505433281 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php
@@ -22,11 +22,6 @@ class InitialConfigSourceTest extends \PHPUnit_Framework_TestCase
*/
private $configType;
- /**
- * @var string
- */
- private $fileKey;
-
/**
* @var InitialConfigSource
*/
@@ -38,8 +33,7 @@ public function setUp()
->disableOriginalConstructor()
->getMock();
$this->configType = 'configType';
- $this->fileKey = 'file.php';
- $this->source = new InitialConfigSource($this->reader, $this->configType, $this->fileKey);
+ $this->source = new InitialConfigSource($this->reader, $this->configType);
}
public function testGet()
@@ -47,7 +41,6 @@ public function testGet()
$path = 'path';
$this->reader->expects($this->once())
->method('load')
- ->with($this->fileKey)
->willReturn([$this->configType => [$path => 'value']]);
$this->assertEquals('value', $this->source->get($path));
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/FileReaderTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/FileReaderTest.php
new file mode 100644
index 0000000000000..dd679c64ce322
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/FileReaderTest.php
@@ -0,0 +1,92 @@
+dirListMock = $this->getMockBuilder(DirectoryList::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->driverPoolMock = $this->getMockBuilder(DriverPool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->configFilePool = $this->getMockBuilder(ConfigFilePool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->driverMock = $this->getMockBuilder(DriverInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->model = new FileReader(
+ $this->dirListMock,
+ $this->driverPoolMock,
+ $this->configFilePool
+ );
+ }
+
+ public function testLoad()
+ {
+ $fileKey = 'configKeyOne';
+
+ $this->dirListMock->expects($this->exactly(2))
+ ->method('getPath')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn(__DIR__ . '/_files');
+ $this->driverPoolMock->expects($this->exactly(2))
+ ->method('getDriver')
+ ->with(DriverPool::FILE)
+ ->willReturn($this->driverMock);
+ $this->configFilePool->expects($this->exactly(2))
+ ->method('getPath')
+ ->willReturnMap([['configKeyOne', 'config.php']]);
+ $this->driverMock->expects($this->exactly(2))
+ ->method('isExists')
+ ->willReturnOnConsecutiveCalls(true, false);
+ $this->configFilePool
+ ->expects($this->any())
+ ->method('getPath')
+ ->willReturnMap([['configKeyOne', 'config.php']]);
+
+ $this->assertSame(['fooKey' => 'foo', 'barKey' => 'bar'], $this->model->load($fileKey));
+ $this->assertSame([], $this->model->load($fileKey));
+ }
+}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php
index 387d3b3ed7467..cdf4f3228b355 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php
@@ -61,10 +61,6 @@ protected function setUp()
->expects($this->any())
->method('getPaths')
->willReturn(['configKeyOne' => 'config.php', 'configKeyTwo' => 'env.php']);
- $this->configFilePool
- ->expects($this->any())
- ->method('getInitialFilePools')
- ->willReturn([]);
}
public function testGetFile()
@@ -107,7 +103,6 @@ public function testCustomLoad($file, $expected)
$configFilePool = $this->getMock(\Magento\Framework\Config\File\ConfigFilePool::class, [], [], '', false);
$configFilePool->expects($this->any())->method('getPaths')->willReturn([$file]);
$configFilePool->expects($this->any())->method('getPath')->willReturn($file);
- $configFilePool->expects($this->any())->method('getInitialFilePools')->willReturn([]);
$object = new Reader($this->dirList, $this->driverPool, $configFilePool, $file);
$this->assertSame($expected, $object->load($file));
}
@@ -122,50 +117,4 @@ public function loadCustomDataProvider()
['nonexistent.php', []],
];
}
-
- /**
- * @expectedException \Exception
- * @expectedExceptionMessage Key collision
- */
- public function testMerging()
- {
- $configFilePool = $this->getMock(\Magento\Framework\Config\File\ConfigFilePool::class, [], [], '', false);
- $files = [['configKeyOne', 'mergeOne.php'], ['configKeyTwo','mergeTwo.php']];
- $configFilePool
- ->expects($this->any())
- ->method('getPath')
- ->will($this->returnValueMap($files));
- $configFilePool->expects($this->any())
- ->method('getInitialFilePools')
- ->willReturn([]);
- $configFilePool
- ->expects($this->any())
- ->method('getPaths')
- ->willReturn(['configKeyOne' => 'mergeOne.php', 'configKeyTwo' => 'mergeTwo.php']);
- $object = new Reader($this->dirList, $this->driverPool, $configFilePool);
- $object->load();
- }
-
- /**
- * @expectedException \Exception
- * @expectedExceptionMessage Key collision
- */
- public function testMergingWithDuplicateEndValues()
- {
- $configFilePool = $this->getMock(\Magento\Framework\Config\File\ConfigFilePool::class, [], [], '', false);
- $files = [['configKeyOne', 'config.php'], ['configKeyTwo','duplicateConfig.php']];
- $configFilePool
- ->expects($this->any())
- ->method('getPath')
- ->will($this->returnValueMap($files));
- $configFilePool->expects($this->any())
- ->method('getInitialFilePools')
- ->willReturn([]);
- $configFilePool
- ->expects($this->any())
- ->method('getPaths')
- ->willReturn(['configKeyOne' => 'config.php', 'configKeyTwo' => 'duplicateConfig.php']);
- $object = new Reader($this->dirList, $this->driverPool, $configFilePool);
- $object->load();
- }
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/WriterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/WriterTest.php
index adb43c3b74a30..76301ea44bb79 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/WriterTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/WriterTest.php
@@ -3,7 +3,6 @@
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-
namespace Magento\Framework\App\Test\Unit\DeploymentConfig;
use Magento\Framework\App\DeploymentConfig;
@@ -17,45 +16,71 @@
use Magento\Framework\Filesystem\Directory\ReadInterface;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\Framework\Phrase;
+use PHPUnit_Framework_MockObject_MockObject as Mock;
/**
- * @covers \Magento\Framework\App\DeploymentConfig\Writer
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @package Magento\Framework\App\Test\Unit\DeploymentConfig
*/
class WriterTest extends \PHPUnit_Framework_TestCase
{
- /** @var Writer */
+ /**
+ * @var Writer
+ */
private $object;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /**
+ * @var DeploymentConfig\Reader|Mock
+ */
private $reader;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /**
+ * @var WriteInterface|Mock
+ */
private $dirWrite;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /**
+ * @var ReadInterface|Mock
+ */
private $dirRead;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
+ /**
+ * @var FormatterInterface|Mock
+ */
protected $formatter;
- /** @var ConfigFilePool */
+ /**
+ * @var ConfigFilePool|Mock
+ */
private $configFilePool;
- /** @var DeploymentConfig */
+ /**
+ * @var DeploymentConfig|Mock
+ */
private $deploymentConfig;
- /** @var Filesystem */
+ /**
+ * @var Filesystem|Mock
+ */
private $filesystem;
protected function setUp()
{
- $this->reader = $this->getMock(Reader::class, [], [], '', false);
- $this->filesystem = $this->getMock(Filesystem::class, [], [], '', false);
+ $this->reader = $this->getMockBuilder(Reader::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->filesystem = $this->getMockBuilder(Filesystem::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->formatter = $this->getMockForAbstractClass(FormatterInterface::class);
- $this->configFilePool = $this->getMock(ConfigFilePool::class, [], [], '', false);
- $this->deploymentConfig = $this->getMock(DeploymentConfig::class, [], [], '', false);
+ $this->configFilePool = $this->getMockBuilder(ConfigFilePool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->deploymentConfig = $this->getMockBuilder(DeploymentConfig::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->dirWrite = $this->getMockForAbstractClass(WriteInterface::class);
+ $this->dirRead = $this->getMockForAbstractClass(ReadInterface::class);
+
$this->object = new Writer(
$this->reader,
$this->filesystem,
@@ -63,19 +88,6 @@ protected function setUp()
$this->deploymentConfig,
$this->formatter
);
- $this->reader->expects($this->any())->method('getFiles')->willReturn('test.php');
- $this->dirWrite = $this->getMockForAbstractClass(WriteInterface::class);
- $this->dirRead = $this->getMockForAbstractClass(ReadInterface::class);
- $this->dirRead->expects($this->any())
- ->method('getAbsolutePath');
- $this->filesystem->expects($this->any())
- ->method('getDirectoryWrite')
- ->with(DirectoryList::CONFIG)
- ->willReturn($this->dirWrite);
- $this->filesystem->expects($this->any())
- ->method('getDirectoryRead')
- ->with(DirectoryList::CONFIG)
- ->willReturn($this->dirRead);
}
public function testSaveConfig()
@@ -83,7 +95,6 @@ public function testSaveConfig()
$configFiles = [
ConfigFilePool::APP_CONFIG => 'config.php'
];
-
$testSetExisting = [
ConfigFilePool::APP_CONFIG => [
'foo' => 'bar',
@@ -94,7 +105,6 @@ public function testSaveConfig()
]
],
];
-
$testSetUpdate = [
ConfigFilePool::APP_CONFIG => [
'baz' => [
@@ -102,7 +112,6 @@ public function testSaveConfig()
]
],
];
-
$testSetExpected = [
ConfigFilePool::APP_CONFIG => [
'foo' => 'bar',
@@ -114,17 +123,37 @@ public function testSaveConfig()
],
];
- $this->deploymentConfig->expects($this->once())->method('resetData');
- $this->configFilePool->expects($this->once())->method('getPaths')->willReturn($configFiles);
- $this->dirWrite->expects($this->any())->method('isExist')->willReturn(true);
- $this->reader->expects($this->once())->method('loadConfigFile')
+ $this->deploymentConfig->expects($this->once())
+ ->method('resetData');
+ $this->configFilePool->expects($this->once())
+ ->method('getPaths')
+ ->willReturn($configFiles);
+ $this->dirWrite->expects($this->any())
+ ->method('isExist')
+ ->willReturn(true);
+ $this->reader->expects($this->once())
+ ->method('load')
->willReturn($testSetExisting[ConfigFilePool::APP_CONFIG]);
- $this->formatter
- ->expects($this->once())
+ $this->formatter->expects($this->once())
->method('format')
->with($testSetExpected[ConfigFilePool::APP_CONFIG])
->willReturn([]);
- $this->dirWrite->expects($this->once())->method('writeFile')->with('config.php', []);
+ $this->dirWrite->expects($this->once())
+ ->method('writeFile')
+ ->with('config.php', []);
+ $this->reader->expects($this->any())
+ ->method('getFiles')
+ ->willReturn('test.php');
+ $this->dirRead->expects($this->any())
+ ->method('getAbsolutePath');
+ $this->filesystem->expects($this->any())
+ ->method('getDirectoryWrite')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn($this->dirWrite);
+ $this->filesystem->expects($this->any())
+ ->method('getDirectoryRead')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn($this->dirRead);
$this->object->saveConfig($testSetUpdate);
}
@@ -134,7 +163,6 @@ public function testSaveConfigOverride()
$configFiles = [
ConfigFilePool::APP_CONFIG => 'config.php'
];
-
$testSetUpdate = [
ConfigFilePool::APP_CONFIG => [
'baz' => [
@@ -142,7 +170,6 @@ public function testSaveConfigOverride()
]
],
];
-
$testSetExpected = [
ConfigFilePool::APP_CONFIG => [
'baz' => [
@@ -151,15 +178,34 @@ public function testSaveConfigOverride()
],
];
- $this->deploymentConfig->expects($this->once())->method('resetData');
- $this->configFilePool->expects($this->once())->method('getPaths')->willReturn($configFiles);
- $this->dirWrite->expects($this->any())->method('isExist')->willReturn(true);
- $this->formatter
- ->expects($this->once())
+ $this->deploymentConfig->expects($this->once())
+ ->method('resetData');
+ $this->configFilePool->expects($this->once())
+ ->method('getPaths')
+ ->willReturn($configFiles);
+ $this->dirWrite->expects($this->any())
+ ->method('isExist')
+ ->willReturn(true);
+ $this->formatter->expects($this->once())
->method('format')
->with($testSetExpected[ConfigFilePool::APP_CONFIG])
->willReturn([]);
- $this->dirWrite->expects($this->once())->method('writeFile')->with('config.php', []);
+ $this->dirWrite->expects($this->once())
+ ->method('writeFile')
+ ->with('config.php', []);
+ $this->reader->expects($this->any())
+ ->method('getFiles')
+ ->willReturn('test.php');
+ $this->dirRead->expects($this->any())
+ ->method('getAbsolutePath');
+ $this->filesystem->expects($this->any())
+ ->method('getDirectoryWrite')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn($this->dirWrite);
+ $this->filesystem->expects($this->any())
+ ->method('getDirectoryRead')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn($this->dirRead);
$this->object->saveConfig($testSetUpdate, true);
}
@@ -170,9 +216,29 @@ public function testSaveConfigOverride()
*/
public function testSaveConfigException()
{
- $this->configFilePool->method('getPaths')->willReturn([ConfigFilePool::APP_ENV => 'env.php']);
$exception = new FileSystemException(new Phrase('error when writing file config file'));
- $this->dirWrite->method('writeFile')->willThrowException($exception);
+
+ $this->configFilePool->method('getPaths')
+ ->willReturn([ConfigFilePool::APP_ENV => 'env.php']);
+ $this->dirWrite->method('writeFile')
+ ->willThrowException($exception);
+ $this->reader->expects($this->any())
+ ->method('getFiles')
+ ->willReturn('test.php');
+ $this->dirRead->expects($this->any())
+ ->method('getAbsolutePath');
+ $this->filesystem->expects($this->any())
+ ->method('getDirectoryWrite')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn($this->dirWrite);
+ $this->filesystem->expects($this->any())
+ ->method('getDirectoryRead')
+ ->with(DirectoryList::CONFIG)
+ ->willReturn($this->dirRead);
+ $this->dirWrite->expects($this->any())
+ ->method('isExist')
+ ->willReturn(true);
+
$this->object->saveConfig([ConfigFilePool::APP_ENV => ['key' => 'value']]);
}
}
diff --git a/lib/internal/Magento/Framework/Config/File/ConfigFilePool.php b/lib/internal/Magento/Framework/Config/File/ConfigFilePool.php
index 8f39247426015..ec505a7c6ef27 100644
--- a/lib/internal/Magento/Framework/Config/File/ConfigFilePool.php
+++ b/lib/internal/Magento/Framework/Config/File/ConfigFilePool.php
@@ -14,7 +14,14 @@ class ConfigFilePool
const APP_CONFIG = 'app_config';
const APP_ENV = 'app_env';
+ /**
+ * @deprecated Magento does not support custom config file pools since 2.2.0 version
+ */
const LOCAL = 'local';
+
+ /**
+ * @deprecated Magento does not support custom config file pools since 2.2.0 version
+ */
const DIST = 'dist';
/**
@@ -31,6 +38,7 @@ class ConfigFilePool
* Initial files for configuration
*
* @var array
+ * @deprecated Magento does not support custom config file pools since 2.2.0 version
*/
private $initialConfigFiles = [
self::DIST => [
@@ -82,6 +90,7 @@ public function getPath($fileKey)
* Returns application initial config files.
*
* @return array
+ * @deprecated Magento does not support custom config file pools since 2.2.0 version
*/
public function getInitialFilePools()
{
@@ -93,6 +102,7 @@ public function getInitialFilePools()
*
* @param string $pool
* @return array
+ * @deprecated Magento does not support custom config file pools since 2.2.0 version
*/
public function getPathsByPool($pool)
{
diff --git a/lib/internal/Magento/Framework/Locale/AvailableLocalesInterface.php b/lib/internal/Magento/Framework/Locale/AvailableLocalesInterface.php
new file mode 100644
index 0000000000000..111232365086a
--- /dev/null
+++ b/lib/internal/Magento/Framework/Locale/AvailableLocalesInterface.php
@@ -0,0 +1,23 @@
+fileSystem = $fileSystem;
+ $this->flyweightFactory = $flyweightFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * If theme or file directory for theme static content does not exist then return an empty array.
+ */
+ public function getList($code, $area = DesignInterface::DEFAULT_AREA)
+ {
+ try {
+ $theme = $this->flyweightFactory->create($code, $area);
+ $reader = $this->fileSystem->getDirectoryRead(DirectoryList::STATIC_VIEW);
+ $dirs = $reader->read($theme->getFullPath());
+ } catch (\Exception $e) {
+ return [];
+ }
+
+ return array_map('basename', $dirs);
+ }
+}
diff --git a/lib/internal/Magento/Framework/Locale/Deployed/Options.php b/lib/internal/Magento/Framework/Locale/Deployed/Options.php
new file mode 100644
index 0000000000000..f2e05407cb87c
--- /dev/null
+++ b/lib/internal/Magento/Framework/Locale/Deployed/Options.php
@@ -0,0 +1,133 @@
+localeLists = $localeLists;
+ $this->state = $state;
+ $this->availableLocales = $availableLocales;
+ $this->design = $design;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOptionLocales()
+ {
+ return $this->filterLocales($this->localeLists->getOptionLocales());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTranslatedOptionLocales()
+ {
+ return $this->filterLocales($this->localeLists->getTranslatedOptionLocales());
+ }
+
+ /**
+ * Filter list of locales by available locales for current theme and depends on running application mode.
+ *
+ * Applies filters only in production mode.
+ * For example, if the current design theme has only one generated locale en_GB then for given array of locales:
+ * ```php
+ * $locales = [
+ * 0 => [
+ * 'value' => 'da_DK'
+ * 'label' => 'Danish (Denmark)'
+ * ],
+ * 1 => [
+ * 'value' => 'de_DE'
+ * 'label' => 'German (Germany)'
+ * ],
+ * 2 => [
+ * 'value' => 'en_GB'
+ * 'label' => 'English (United Kingdom)'
+ * ],
+ * ]
+ * ```
+ * result will be:
+ * ```php
+ * [
+ * 2 => [
+ * 'value' => 'en_GB'
+ * 'label' => 'English (United Kingdom)'
+ * ],
+ * ]
+ * ```
+ *
+ * @param array $locales list of locales for filtering
+ * @return array of filtered locales
+ */
+ private function filterLocales(array $locales)
+ {
+ if ($this->state->getMode() != State::MODE_PRODUCTION) {
+ return $locales;
+ }
+
+ $theme = $this->design->getDesignTheme();
+ try {
+ $availableLocales = $this->availableLocales->getList($theme->getCode(), $theme->getArea());
+ } catch (LocalizedException $e) {
+ $availableLocales = [];
+ }
+
+ return array_filter($locales, function ($localeData) use ($availableLocales) {
+ return in_array($localeData['value'], $availableLocales);
+ });
+ }
+}
diff --git a/lib/internal/Magento/Framework/Locale/ListsInterface.php b/lib/internal/Magento/Framework/Locale/ListsInterface.php
index e94856db84ac6..cc4d3ee3383a5 100644
--- a/lib/internal/Magento/Framework/Locale/ListsInterface.php
+++ b/lib/internal/Magento/Framework/Locale/ListsInterface.php
@@ -5,22 +5,8 @@
*/
namespace Magento\Framework\Locale;
-interface ListsInterface
+interface ListsInterface extends OptionInterface
{
- /**
- * Get options array for locale dropdown in current locale
- *
- * @return array
- */
- public function getOptionLocales();
-
- /**
- * Get translated to original locale options array for locale dropdown
- *
- * @return array
- */
- public function getTranslatedOptionLocales();
-
/**
* Retrieve timezone option list
*
diff --git a/lib/internal/Magento/Framework/Locale/OptionInterface.php b/lib/internal/Magento/Framework/Locale/OptionInterface.php
new file mode 100644
index 0000000000000..0e1b7cd8a9d52
--- /dev/null
+++ b/lib/internal/Magento/Framework/Locale/OptionInterface.php
@@ -0,0 +1,54 @@
+ [
+ * 'value' => 'de_DE'
+ * 'label' => 'German (Germany)'
+ * ],
+ * 1 => [
+ * 'value' => 'en_GB'
+ * 'label' => 'English (United Kingdom)'
+ * ],
+ * ]
+ * ```
+ *
+ * @return array
+ */
+ public function getOptionLocales();
+
+ /**
+ * Get array of deployed locales with translation.
+ *
+ * Function result has next format:
+ * ```php
+ * [
+ * 0 => [
+ * 'value' => 'de_DE'
+ * 'label' => 'Deutsch (Deutschland) / German (Germany)'
+ * ],
+ * 1 => [
+ * 'value' => 'en_GB'
+ * 'label' => 'English (United Kingdom) / English (United Kingdom)'
+ * ],
+ * ]
+ * ```
+ *
+ * @return array
+ */
+ public function getTranslatedOptionLocales();
+}
diff --git a/lib/internal/Magento/Framework/Locale/Test/Unit/Deployed/CodesTest.php b/lib/internal/Magento/Framework/Locale/Test/Unit/Deployed/CodesTest.php
new file mode 100644
index 0000000000000..1190188000f40
--- /dev/null
+++ b/lib/internal/Magento/Framework/Locale/Test/Unit/Deployed/CodesTest.php
@@ -0,0 +1,95 @@
+fileSystemMock = $this->getMockBuilder(Filesystem::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->flyweightFactoryMock = $this->getMockBuilder(FlyweightFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->model = new Codes(
+ $this->flyweightFactoryMock,
+ $this->fileSystemMock
+ );
+ }
+
+ public function testGetList()
+ {
+ $code = 'code';
+ $area = 'area';
+ $fullPath = 'some/full/path';
+
+ $themeMock = $this->getMockBuilder(ThemeInterface::class)
+ ->getMockForAbstractClass();
+ $themeMock->expects($this->once())
+ ->method('getFullPath')
+ ->willReturn($fullPath);
+ $this->flyweightFactoryMock->expects($this->once())
+ ->method('create')
+ ->with($code, $area)
+ ->willReturn($themeMock);
+ $reader = $this->getMockBuilder(ReadInterface::class)
+ ->getMockForAbstractClass();
+ $reader->expects($this->once())
+ ->method('read')
+ ->with($fullPath)
+ ->willReturn([
+ $fullPath . '/de_DE',
+ $fullPath . '/en_US',
+ $fullPath . '/fr_FR'
+ ]);
+ $this->fileSystemMock->expects($this->once())
+ ->method('getDirectoryRead')
+ ->with(DirectoryList::STATIC_VIEW)
+ ->willReturn($reader);
+
+ $this->assertEquals(
+ [
+ 'de_DE',
+ 'en_US',
+ 'fr_FR'
+ ],
+ $this->model->getList($code, $area)
+ );
+ }
+}
diff --git a/lib/internal/Magento/Framework/Locale/Test/Unit/Deployed/OptionsTest.php b/lib/internal/Magento/Framework/Locale/Test/Unit/Deployed/OptionsTest.php
new file mode 100644
index 0000000000000..caf1bb91b752e
--- /dev/null
+++ b/lib/internal/Magento/Framework/Locale/Test/Unit/Deployed/OptionsTest.php
@@ -0,0 +1,206 @@
+stateMock = $this->getMockBuilder(State::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->availableLocalesMock = $this->getMockBuilder(AvailableLocalesInterface::class)
+ ->getMockForAbstractClass();
+ $this->designMock = $this->getMockBuilder(DesignInterface::class)
+ ->getMockForAbstractClass();
+ $this->localeListsMock = $this->getMockBuilder(ListsInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->model = new Options(
+ $this->localeListsMock,
+ $this->stateMock,
+ $this->availableLocalesMock,
+ $this->designMock
+ );
+ }
+
+ /**
+ * @param string $mode
+ * @param array $locales
+ * @param array $expectedLocales
+ * @param array $deployedCodes
+ * @dataProvider getLocaleDataProvider
+ */
+ public function testGetOptionLocales($mode, $locales, $expectedLocales, $deployedCodes)
+ {
+ $this->localeListsMock->expects($this->once())
+ ->method('getOptionLocales')
+ ->willReturn($locales);
+
+ $this->prepareGetLocales($mode, $deployedCodes);
+
+ $this->assertEquals($expectedLocales, array_values($this->model->getOptionLocales()));
+ }
+
+ /**
+ * @param string $mode
+ * @param array $locales
+ * @param array $expectedLocales
+ * @param array $deployedCodes
+ * @dataProvider getLocaleDataProvider
+ */
+ public function testGetTranslatedOptionLocales($mode, $locales, $expectedLocales, $deployedCodes)
+ {
+ $this->localeListsMock->expects($this->once())
+ ->method('getTranslatedOptionLocales')
+ ->willReturn($locales);
+
+ $this->prepareGetLocales($mode, $deployedCodes);
+
+ $this->assertEquals($expectedLocales, array_values($this->model->getTranslatedOptionLocales()));
+ }
+
+ /**
+ * @param $mode
+ * @param $deployedCodes
+ * @return void
+ */
+ private function prepareGetLocales($mode, $deployedCodes)
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getMode')
+ ->willReturn($mode);
+
+ if ($mode == State::MODE_PRODUCTION) {
+ $area = 'area';
+ $code = 'code';
+ $themeMock = $this->getMockBuilder(ThemeInterface::class)
+ ->getMockForAbstractClass();
+ $themeMock->expects($this->once())
+ ->method('getCode')
+ ->willReturn($code);
+ $themeMock->expects($this->once())
+ ->method('getArea')
+ ->willReturn($area);
+ $this->designMock->expects($this->once())
+ ->method('getDesignTheme')
+ ->willReturn($themeMock);
+ $this->availableLocalesMock->expects($this->once())
+ ->method('getList')
+ ->with($code, $area)
+ ->willReturn($deployedCodes);
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function getLocaleDataProvider()
+ {
+ return [
+ [
+ State::MODE_PRODUCTION,
+ [
+ [
+ 'value' => 'da_DK',
+ 'label' => 'Danish (Denmark)'
+ ],
+ [
+ 'value' => 'de_DE',
+ 'label' => 'German (German)'
+ ]
+ ],
+ [
+ [
+ 'value' => 'de_DE',
+ 'label' => 'German (German)'
+ ]
+ ],
+ [
+ 'de_DE'
+ ]
+ ],
+ [
+ State::MODE_PRODUCTION,
+ [
+ [
+ 'value' => 'de_DE',
+ 'label' => 'German (German)'
+ ]
+ ],
+ [],
+ []
+ ],
+ [
+ State::MODE_DEVELOPER,
+ [
+ [
+ 'value' => 'da_DK',
+ 'label' => 'Danish (Denmark)'
+ ],
+ [
+ 'value' => 'de_DE',
+ 'label' => 'German (German)'
+ ]
+ ],
+ [
+ [
+ 'value' => 'da_DK',
+ 'label' => 'Danish (Denmark)'
+ ],
+ [
+ 'value' => 'de_DE',
+ 'label' => 'German (German)'
+ ]
+ ],
+ [
+ 'de_DE'
+ ]
+ ],
+ ];
+ }
+}
diff --git a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php
index 4d485fc93368d..d4e4be4a58790 100644
--- a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php
@@ -7,9 +7,13 @@
use Magento\Framework\Setup\ConsoleLogger;
use Magento\Setup\Model\InstallerFactory;
+use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Deploy\Console\Command\App\ConfigImportCommand;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Framework\App\ObjectManager;
/**
* Command for updating installed application after the code base has changed
@@ -28,14 +32,21 @@ class UpgradeCommand extends AbstractSetupCommand
*/
private $installerFactory;
+ /**
+ * @var DeploymentConfig
+ */
+ private $deploymentConfig;
+
/**
* Constructor
*
* @param InstallerFactory $installerFactory
+ * @param DeploymentConfig $deploymentConfig
*/
- public function __construct(InstallerFactory $installerFactory)
+ public function __construct(InstallerFactory $installerFactory, DeploymentConfig $deploymentConfig = null)
{
$this->installerFactory = $installerFactory;
+ $this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get(DeploymentConfig::class);
parent::__construct();
}
@@ -65,13 +76,25 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $keepGenerated = $input->getOption(self::INPUT_KEY_KEEP_GENERATED);
- $installer = $this->installerFactory->create(new ConsoleLogger($output));
- $installer->updateModulesSequence($keepGenerated);
- $installer->installSchema();
- $installer->installDataFixtures();
- if (!$keepGenerated) {
- $output->writeln('Please re-run Magento compile command. Use the command "setup:di:compile"');
+ try {
+ $keepGenerated = $input->getOption(self::INPUT_KEY_KEEP_GENERATED);
+ $installer = $this->installerFactory->create(new ConsoleLogger($output));
+ $installer->updateModulesSequence($keepGenerated);
+ $installer->installSchema();
+ $installer->installDataFixtures();
+ if (!$keepGenerated) {
+ $output->writeln(
+ 'Please re-run Magento compile command. Use the command "setup:di:compile"'
+ );
+ }
+
+ if ($this->deploymentConfig->isAvailable()) {
+ $importConfigCommand = $this->getApplication()->find(ConfigImportCommand::COMMAND_NAME);
+ $importConfigCommand->run(new ArrayInput([]), $output);
+ }
+ } catch (\Exception $e) {
+ $output->writeln($e->getMessage());
+ return \Magento\Framework\Console\Cli::RETURN_FAILURE;
}
return \Magento\Framework\Console\Cli::RETURN_SUCCESS;
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php
index 2277a4b0a1bc0..1119d08c57086 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php
@@ -8,25 +8,73 @@
use Magento\Setup\Console\Command\UpgradeCommand;
use Symfony\Component\Console\Tester\CommandTester;
use Magento\Framework\Console\Cli;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Setup\Model\InstallerFactory;
+use Magento\Setup\Model\Installer;
class UpgradeCommandTest extends \PHPUnit_Framework_TestCase
{
/**
- * @param array $options
- * @param string $expectedString
+ * @var DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $deploymentConfigMock;
+
+ /**
+ * @var InstallerFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $installerFactoryMock;
+
+ /**
+ * @var Installer|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $installerMock;
+
+ /**
+ * @var UpgradeCommand
+ */
+ private $upgradeCommand;
+
+ /**
+ * @var CommandTester
+ */
+ private $commandTester;
+
+ /**
+ * @return void
+ */
+ protected function setUp()
+ {
+ $this->deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->installerFactoryMock = $this->getMockBuilder(InstallerFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->installerMock = $this->getMockBuilder(Installer::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->installerFactoryMock->expects($this->once())
+ ->method('create')
+ ->willReturn($this->installerMock);
+
+ $this->upgradeCommand = new UpgradeCommand($this->installerFactoryMock, $this->deploymentConfigMock);
+ $this->commandTester = new CommandTester($this->upgradeCommand);
+ }
+
+ /**
* @dataProvider executeDataProvider
*/
- public function testExecute($options = [], $expectedString = '')
+ public function testExecute($options, $expectedString = '')
{
- $installerFactory = $this->getMock(\Magento\Setup\Model\InstallerFactory::class, [], [], '', false);
- $installer = $this->getMock(\Magento\Setup\Model\Installer::class, [], [], '', false);
- $installer->expects($this->at(0))->method('updateModulesSequence');
- $installer->expects($this->at(1))->method('installSchema');
- $installer->expects($this->at(2))->method('installDataFixtures');
- $installerFactory->expects($this->once())->method('create')->willReturn($installer);
- $commandTester = new CommandTester(new UpgradeCommand($installerFactory));
- $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->execute($options));
- $this->assertEquals($expectedString, $commandTester->getDisplay());
+ $this->installerMock->expects($this->at(0))
+ ->method('updateModulesSequence');
+ $this->installerMock->expects($this->at(1))
+ ->method('installSchema');
+ $this->installerMock->expects($this->at(2))
+ ->method('installDataFixtures');
+
+ $this->assertSame(Cli::RETURN_SUCCESS, $this->commandTester->execute($options));
+ $this->assertEquals($expectedString, $this->commandTester->getDisplay());
}
/**