From 361a2308699fd3e4295b6bd13deb6c804f979a0b Mon Sep 17 00:00:00 2001 From: Oleh Posyniak Date: Wed, 2 Nov 2016 11:03:04 +0200 Subject: [PATCH 1/8] MAGETWO-59809: Scrub sensitive data during app:dump --- app/code/Magento/Authorizenet/etc/di.xml | 10 ++ app/code/Magento/Backend/etc/di.xml | 18 +++ app/code/Magento/Braintree/etc/di.xml | 12 ++ app/code/Magento/Checkout/etc/di.xml | 7 + .../Source/DumpConfigSourceAggregated.php | 148 ++++++++++++++++++ .../Source/DumpConfigSourceInterface.php | 21 +++ .../Magento/Config/App/Config/Type/System.php | 13 +- .../Config/Block/System/Config/Form.php | 55 +++++-- .../Config/Model/Config/Export/Comment.php | 61 ++++++++ .../Model/Config/Export/ExcludeList.php | 53 +++++++ .../Processor/EnvironmentPlaceholder.php | 65 ++++++++ .../Reader/Source/Deployed/SettingChecker.php | 86 ++++++++-- .../Config/Model/Placeholder/Environment.php | 71 +++++++++ .../Model/Placeholder/PlaceholderFactory.php | 41 +++++ .../Placeholder/PlaceholderInterface.php | 40 +++++ .../Source/DumpConfigSourceAggregatedTest.php | 125 +++++++++++++++ .../Test/Unit/App/Config/Type/SystemTest.php | 16 +- .../Unit/Block/System/Config/FormTest.php | 48 ++++-- .../Unit/Model/Config/Export/CommentTest.php | 88 +++++++++++ .../Model/Config/Export/ExcludeListTest.php | 40 +++++ .../Processor/EnvironmentPlaceholderTest.php | 120 ++++++++++++++ .../Source/Deployed/SettingCheckerTest.php | 118 ++++++++++---- .../Model/Placeholder/EnvironmentTest.php | 103 ++++++++++++ app/code/Magento/Config/etc/di.xml | 29 +++- app/code/Magento/Contact/etc/di.xml | 16 ++ .../Command/App/ApplicationDumpCommand.php | 21 ++- app/code/Magento/Developer/etc/di.xml | 8 + app/code/Magento/Dhl/etc/di.xml | 9 ++ app/code/Magento/Directory/etc/di.xml | 8 + app/code/Magento/Fedex/etc/di.xml | 10 ++ app/code/Magento/NewRelicReporting/etc/di.xml | 10 ++ app/code/Magento/Paypal/etc/di.xml | 29 ++++ app/code/Magento/ProductAlert/etc/di.xml | 8 + app/code/Magento/ProductVideo/etc/di.xml | 7 + app/code/Magento/Sales/etc/di.xml | 14 ++ app/code/Magento/Shipping/etc/di.xml | 12 ++ app/code/Magento/Sitemap/etc/di.xml | 7 + app/code/Magento/Ups/etc/di.xml | 21 +++ app/code/Magento/Usps/etc/di.xml | 19 +++ .../Processor/EnvironmentPlaceholderTest.php | 103 ++++++++++++ .../App/ApplicationDumpCommandTest.php | 73 +++++++-- .../Magento/Deploy/_files/config_data.php | 33 ++++ lib/internal/Magento/Framework/App/Config.php | 2 +- .../Framework/App/Config/CommentInterface.php | 21 +++ .../App/Config/PreProcessorComposite.php | 40 +++++ .../App/Config/Spi/PreProcessorInterface.php | 20 +++ .../Framework/App/DeploymentConfig/Reader.php | 16 +- .../Framework/App/DeploymentConfig/Writer.php | 5 +- .../Writer/FormatterInterface.php | 3 +- .../DeploymentConfig/Writer/PhpFormatter.php | 14 +- .../Unit/Config/PreProcessorCompositeTest.php | 40 +++++ .../Writer/PhpFormatterTest.php | 121 +++++++++++++- 52 files changed, 1974 insertions(+), 104 deletions(-) create mode 100644 app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php create mode 100644 app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php create mode 100644 app/code/Magento/Config/Model/Config/Export/Comment.php create mode 100644 app/code/Magento/Config/Model/Config/Export/ExcludeList.php create mode 100644 app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php create mode 100644 app/code/Magento/Config/Model/Placeholder/Environment.php create mode 100644 app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php create mode 100644 app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php create mode 100644 app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php create mode 100644 app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php create mode 100644 app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php create mode 100644 app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php create mode 100644 app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php create mode 100644 app/code/Magento/Contact/etc/di.xml create mode 100644 app/code/Magento/Ups/etc/di.xml create mode 100644 app/code/Magento/Usps/etc/di.xml create mode 100644 dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php create mode 100644 lib/internal/Magento/Framework/App/Config/CommentInterface.php create mode 100644 lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php create mode 100644 lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php create mode 100644 lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php diff --git a/app/code/Magento/Authorizenet/etc/di.xml b/app/code/Magento/Authorizenet/etc/di.xml index f5e595fb450e8..287cdec6fa0f7 100644 --- a/app/code/Magento/Authorizenet/etc/di.xml +++ b/app/code/Magento/Authorizenet/etc/di.xml @@ -16,4 +16,14 @@ Magento\Authorizenet\Model\Directpost\Session\Storage + + + + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Backend/etc/di.xml b/app/code/Magento/Backend/etc/di.xml index 7307bbe09f1b4..8881eb10708bb 100644 --- a/app/code/Magento/Backend/etc/di.xml +++ b/app/code/Magento/Backend/etc/di.xml @@ -214,4 +214,22 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml index def12ff4c8a7e..c8041faf7cb8e 100644 --- a/app/code/Magento/Braintree/etc/di.xml +++ b/app/code/Magento/Braintree/etc/di.xml @@ -434,4 +434,16 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Checkout/etc/di.xml b/app/code/Magento/Checkout/etc/di.xml index a2243b33a04ed..81a430d52c499 100644 --- a/app/code/Magento/Checkout/etc/di.xml +++ b/app/code/Magento/Checkout/etc/di.xml @@ -42,4 +42,11 @@ + + + + 1 + + + diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php new file mode 100644 index 0000000000000..41196b78567b9 --- /dev/null +++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php @@ -0,0 +1,148 @@ +excludeList = $excludeList; + $this->sources = $sources; + } + + /** + * Retrieve aggregated configuration from all available sources. + * + * @param string $path + * @return array + */ + public function get($path = '') + { + $path = (string)$path; + $data = []; + + if (isset($this->data[$path])) { + return $this->data[$path]; + } + + $this->sortSources(); + + foreach ($this->sources as $sourceConfig) { + /** @var ConfigSourceInterface $source */ + $source = $sourceConfig['source']; + $data = array_replace_recursive($data, $source->get($path)); + } + + $this->excludedFields = []; + $this->filterChain($path, $data); + + return $this->data[$path] = $data; + } + + /** + * Recursive filtering of sensitive data + * + * @param string $path + * @param array $data + */ + private function filterChain($path, &$data) + { + foreach ($data as $subKey => &$subData) { + $newPath = $path ? $path . '/' . $subKey : $subKey; + $filteredPath = $this->filterPath($newPath); + + if ( + $filteredPath + && !is_array($data[$subKey]) + && $this->excludeList->isPresent($filteredPath) + ) { + $this->excludedFields[$newPath] = $filteredPath; + + unset($data[$subKey]); + } elseif (is_array($subData)) { + $this->filterChain($newPath, $subData); + } + } + } + + /** + * Eliminating scope info from path + * + * @param string $path + * @return null|string + */ + private function filterPath($path) + { + $parts = explode('/', $path); + + // Check if there are enough parts to recognize scope + if (count($parts) < 3) { + return null; + } + + if ($parts[0] === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + unset($parts[0]); + } else { + unset($parts[0], $parts[1]); + } + + return implode('/', $parts); + } + + /** + * Sort sources + * + * @return void + */ + private function sortSources() + { + uasort($this->sources, function ($firstItem, $secondItem) { + return $firstItem['sortOrder'] > $secondItem['sortOrder']; + }); + } + + /** + * Retrieves list of field paths were excluded from config dump + * @return array + */ + public function getExcludedFields() + { + $this->get(); + + $fields = array_values($this->excludedFields); + $fields = array_unique($fields); + + return $fields; + } +} diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php new file mode 100644 index 0000000000000..cf0ce492b7d52 --- /dev/null +++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceInterface.php @@ -0,0 +1,21 @@ +source = $source; $this->postProcessor = $postProcessor; + $this->preProcessor = $preProcessor; $this->cache = $cache; $this->cachingNestedLevel = $cachingNestedLevel; $this->fallback = $fallback; @@ -86,7 +95,9 @@ public function get($path = '') if (!$this->data) { $data = $this->cache->load(self::CONFIG_TYPE); if (!$data) { - $data = $this->fallback->process($this->source->get()); + $data = $this->preProcessor->process($this->source->get()); + $this->data = new DataObject($data); + $data = $this->fallback->process($data); $this->data = new DataObject($data); $data = $this->postProcessor->process($data); $this->data = new DataObject($data); diff --git a/app/code/Magento/Config/Block/System/Config/Form.php b/app/code/Magento/Config/Block/System/Config/Form.php index 68b8bd5f7c53c..3ba73379143a1 100644 --- a/app/code/Magento/Config/Block/System/Config/Form.php +++ b/app/code/Magento/Config/Block/System/Config/Form.php @@ -7,8 +7,10 @@ use Magento\Config\App\Config\Type\System; use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; +use Magento\Framework\DataObject; /** * System config form block @@ -333,6 +335,16 @@ protected function _initElement( ) { $inherit = true; $data = $this->getAppConfigDataValue($path); + + $placeholderValue = $this->getSettingChecker()->getPlaceholderValue( + $path, + $this->getScope(), + $this->getStringScopeCode() + ); + + if ($placeholderValue) { + $data = $placeholderValue; + } if ($data === null) { if (array_key_exists($path, $this->_configData)) { $data = $this->_configData[$path]; @@ -373,9 +385,7 @@ protected function _initElement( $sharedClass = $this->_getSharedCssClass($field); $requiresClass = $this->_getRequiresCssClass($field, $fieldPrefix); - $isReadOnly = $this->getSettingChecker()->isReadOnly($path, $this->getScope(), $this->getScopeCode()); - $canUseDefault = $this->canUseDefaultValue($field->showInDefault()); - $canUseWebsite = $this->canUseWebsiteValue($field->showInWebsite()); + $isReadOnly = $this->getSettingChecker()->isReadOnly($path, $this->getScope(), $this->getStringScopeCode()); $formField = $fieldset->addField( $elementId, $field->getType(), @@ -392,8 +402,8 @@ protected function _initElement( 'scope' => $this->getScope(), 'scope_id' => $this->getScopeId(), 'scope_label' => $this->getScopeLabel($field), - 'can_use_default_value' => $canUseDefault, - 'can_use_website_value' => $canUseWebsite, + 'can_use_default_value' => $this->canUseDefaultValue($field->showInDefault()), + 'can_use_website_value' => $this->canUseWebsiteValue($field->showInWebsite()), 'can_restore_to_default' => $this->isCanRestoreToDefault($field->canRestore()), 'disabled' => $isReadOnly, 'is_disable_inheritance' => $isReadOnly @@ -413,6 +423,28 @@ protected function _initElement( $formField->setRenderer($fieldRenderer); } + /** + * Retrieve Scope string code + * + * @return string + */ + private function getStringScopeCode() + { + $scopeCode = $this->getData('scope_string_code'); + if (null === $scopeCode) { + if ($this->getStoreCode()) { + $scopeCode = $this->_storeManager->getStore($this->getStoreCode())->getCode(); + } elseif ($this->getWebsiteCode()) { + $scopeCode = $this->_storeManager->getWebsite($this->getWebsiteCode())->getCode(); + } else { + $scopeCode = ''; + } + $this->setScopeStringCode($scopeCode); + } + + return $scopeCode; + } + /** * Populate dependencies block * @@ -748,14 +780,13 @@ private function getAppConfigDataValue($path) { $appConfig = $this->getAppConfig()->get(System::CONFIG_TYPE); $scope = $this->getScope(); - $scopeId = $this->getScopeId(); - if ($scope === 'default') { - $data = isset($appConfig[$scope][$path]) ? $appConfig[$scope][$path] : null; + $scopeCode = $this->getStringScopeCode(); + + if ($scope === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + $data = new DataObject(isset($appConfig[$scope]) ? $appConfig[$scope] : []); } else { - $data = isset($appConfig[$scope][$scopeId][$path]) - ? $appConfig[$scope][$scopeId][$path] - : null; + $data = new DataObject(isset($appConfig[$scope][$scopeCode]) ? $appConfig[$scope][$scopeCode] : []); } - return $data; + return $data->getData($path); } } diff --git a/app/code/Magento/Config/Model/Config/Export/Comment.php b/app/code/Magento/Config/Model/Config/Export/Comment.php new file mode 100644 index 0000000000000..e08657aa4ba7e --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Export/Comment.php @@ -0,0 +1,61 @@ +placeholder = $placeholderFactory->create(Environment::class); + $this->source = $source; + } + + /** + * Retrieves comments for config export file. + * + * @return string + */ + public function get() + { + $comment = ''; + $fields = $this->source->getExcludedFields(); + foreach ($fields as $path) { + $comment .= "\n" . $this->placeholder->generate($path) . ' for ' . $path ; + } + if ($comment) { + $comment = 'The configuration file doesn\'t contain the sensitive data by security reason. ' + . 'The sensitive data can be stored in the next environment variables:' + . $comment; + } + return $comment; + } +} diff --git a/app/code/Magento/Config/Model/Config/Export/ExcludeList.php b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php new file mode 100644 index 0000000000000..4d28036a00946 --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php @@ -0,0 +1,53 @@ +configs = $configs; + } + + /** + * Check whether config item is excluded from export + * + * @param string $path + * @return bool + */ + public function isPresent($path) + { + return !empty($this->configs[$path]) ; + } + + /** + * Retrieves all excluded field paths for export + * + * @return array + */ + public function get() + { + return array_keys(array_filter( + $this->configs, + function ($value) { + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + }) + ); + } +} diff --git a/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php new file mode 100644 index 0000000000000..798d557c43767 --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php @@ -0,0 +1,65 @@ +placeholderFactory = $placeholderFactory; + $this->arrayManager = $arrayManager; + $this->placeholder = $placeholderFactory->create(Environment::class); + } + + /** + * @inheritdoc + */ + public function process(array $config) + { + $environmentVariables = $_ENV; + + foreach ($environmentVariables as $template => $value) { + if (!$this->placeholder->isApplicable($template)) { + continue; + } + + $config = $this->arrayManager->set( + $this->placeholder->restore($template), + $config, + $value + ); + } + + return $config; + } +} diff --git a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php index 510eeab6f3a1b..b1fe859fcadc4 100644 --- a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php +++ b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php @@ -6,10 +6,12 @@ namespace Magento\Config\Model\Config\Reader\Source\Deployed; use Magento\Config\Model\Config\Reader; -use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\DeploymentConfig; -use Magento\Framework\App\ObjectManager; +use Magento\Config\Model\Placeholder\PlaceholderInterface; +use Magento\Config\Model\Placeholder\PlaceholderFactory; +use Magento\Config\Model\Placeholder\Environment; +use Magento\Framework\App\Config\ScopeCodeResolver; /** * Class for checking settings that defined in config file @@ -21,6 +23,16 @@ class SettingChecker */ private $config; + /** + * @var PlaceholderInterface + */ + private $placeholder; + + /** + * @var array|null + */ + private $environmentVariables; + /** * @var ScopeCodeResolver */ @@ -28,16 +40,73 @@ class SettingChecker /** * @param DeploymentConfig $config + * @param PlaceholderFactory $placeholderFactory * @param ScopeCodeResolver $scopeCodeResolver */ public function __construct( DeploymentConfig $config, + PlaceholderFactory $placeholderFactory, ScopeCodeResolver $scopeCodeResolver ) { $this->config = $config; $this->scopeCodeResolver = $scopeCodeResolver; + $this->placeholder = $placeholderFactory->create(Environment::class); + } + + /** + * Check that setting defined in deployed configuration + * + * @param string $path + * @param string $scope + * @param string|null $scopeCode + * @return boolean + */ + public function isReadOnly($path, $scope, $scopeCode = null) + { + $config = $this->getEnvValue( + $this->placeholder->generate($path, $scope, $scopeCode), + $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path) + ); + + return $config !== null; } + /** + * Check that there is value for generated placeholder + * + * Placeholder is generated from values of $path, $scope and $scopeCode + * + * @param string $path + * @param string $scope + * @param string|null $scopeCode + * @return mixed + */ + public function getPlaceholderValue($path, $scope, $scopeCode = null) + { + return $this->getEnvValue($this->placeholder->generate($path, $scope, $scopeCode)); + } + + /** + * Retrieve value of environment variable by placeholder + * + * @param string $placeholder + * @param mixed $defaultValue + * @return mixed + */ + public function getEnvValue($placeholder, $defaultValue = null) + { + if (null === $this->environmentVariables) { + $this->environmentVariables = $_ENV; + } + + if ($this->placeholder->isApplicable($placeholder) && isset($this->environmentVariables[$placeholder])) { + return $this->environmentVariables[$placeholder]; + } + + return $defaultValue; + } + + /** * Resolve path by scope and scope code * @@ -55,17 +124,4 @@ private function resolvePath($scope, $scopeCode) return $scopePath; } - - /** - * Check that setting defined in deployed configuration - * - * @param string $path - * @param string $scope - * @return boolean - */ - public function isReadOnly($path, $scope, $scopeCode) - { - $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path); - return $config !== null; - } } diff --git a/app/code/Magento/Config/Model/Placeholder/Environment.php b/app/code/Magento/Config/Model/Placeholder/Environment.php new file mode 100644 index 0000000000000..aacc049e60799 --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/Environment.php @@ -0,0 +1,71 @@ +deploymentConfig = $deploymentConfig; + } + + /** + * @inheritdoc + */ + public function generate($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + { + $parts = $scopeType ? [$scopeType] : []; + + if ($scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT && $scopeCode) { + $parts[] = $scopeCode; + } + + $parts[] = $path; + + $template = implode('__', $parts); + $template = str_replace('/', '__', $template); + $template = static::PREFIX . $template; + $template = strtoupper($template); + + return $template; + } + + /** + * @inheritdoc + */ + public function restore($template) + { + $template = str_replace(static::PREFIX, '', $template); + $template = str_replace('__', '/', $template); + $template = strtolower($template); + + return $template; + } + + /** + * @inheritdoc + */ + public function isApplicable($placeholder) + { + return 1 === preg_match('/(' . static::PREFIX . '.*[a-zA-Z_]).*/', $placeholder); + } +} diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php new file mode 100644 index 0000000000000..68e688614c774 --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php @@ -0,0 +1,41 @@ +objectManager = $objectManager; + } + + /** + * Create placeholder + * + * @param string $type + * @return PlaceholderInterface + */ + public function create($type) + { + $object = $this->objectManager->create($type); + + if (!$object instanceof PlaceholderInterface) { + throw new \LogicException('Object is not instance of ' . PlaceholderInterface::class); + } + + return $object; + } +} diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php new file mode 100644 index 0000000000000..286eb0034a550 --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php @@ -0,0 +1,40 @@ +sourceMock = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->sourceMockTwo = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->excludeListMock = $this->getMockBuilder(ExcludeList::class) + ->disableOriginalConstructor() + ->getMock(); + + $sources = [ + [ + 'source' => $this->sourceMockTwo, + 'sortOrder' => 100 + ], + [ + 'source' => $this->sourceMock, + 'sortOrder' => 10 + ], + + ]; + + $this->model = new DumpConfigSourceAggregated($this->excludeListMock, $sources); + } + + public function testGet() + { + $path = ''; + $data = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [ + 'base_url' => 'https://test.local', + ] + ] + ], + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ] + ] + ]; + + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn($data); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->excludeListMock->expects($this->any()) + ->method('isPresent') + ->willReturnMap([ + ['web/unsecure/base_url', false], + ['web/secure/base_url', true], + ['test1/test2/test/3', false] + ]); + + $this->assertEquals( + [ + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ], + ], + 'key' => 'value2', + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [] + ] + ], + ], + $this->model->get($path) + ); + } + +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php index 276082ae8a19c..b8af2b81839ca 100644 --- a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php +++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php @@ -8,6 +8,7 @@ use Magento\Config\App\Config\Type\System; use Magento\Framework\App\Config\ConfigSourceInterface; use Magento\Framework\App\Config\Spi\PostProcessorInterface; +use Magento\Framework\App\Config\Spi\PreProcessorInterface; use Magento\Framework\Cache\FrontendInterface; use Magento\Framework\DataObject; use Magento\Store\Model\Config\Processor\Fallback; @@ -28,6 +29,11 @@ class SystemTest extends \PHPUnit_Framework_TestCase */ private $postProcessor; + /** + * @var PreProcessorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $preProcessor; + /** * @var Fallback|\PHPUnit_Framework_MockObject_MockObject */ @@ -54,11 +60,15 @@ public function setUp() ->getMock(); $this->cache = $this->getMockBuilder(FrontendInterface::class) ->getMockForAbstractClass(); + $this->preProcessor = $this->getMockBuilder(PreProcessorInterface::class) + ->getMockForAbstractClass(); + $this->configType = new System( $this->source, $this->postProcessor, $this->fallback, - $this->cache + $this->cache, + $this->preProcessor ); } @@ -92,6 +102,10 @@ public function testGet($isCached) ->method('process') ->with($data) ->willReturnArgument(0); + $this->preProcessor->expects($this->once()) + ->method('process') + ->with($data) + ->willReturnArgument(0); $this->postProcessor->expects($this->once()) ->method('process') ->with($data) diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php index f21274380ddc0..712fa5ed014ee 100644 --- a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php +++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php @@ -10,6 +10,7 @@ use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; use Magento\Framework\App\DeploymentConfig; +use Magento\Store\Model\StoreManagerInterface; /** * Test System config form block @@ -68,6 +69,11 @@ class FormTest extends \PHPUnit_Framework_TestCase */ protected $_fieldsetFactoryMock; + /** + * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManagerMock; + /** * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) @@ -157,6 +163,9 @@ protected function setUp() false ); + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $context = $helper->getObject( @@ -164,7 +173,8 @@ protected function setUp() [ 'scopeConfig' => $this->_coreConfigMock, 'request' => $requestMock, - 'urlBuilder' => $this->_urlModelMock + 'urlBuilder' => $this->_urlModelMock, + 'storeManager' => $this->storeManagerMock ] ); @@ -419,6 +429,7 @@ public function initGroupDataProvider() * @param string|null $configPath * @param bool $inherit * @param string $expectedValue + * @param string|null $placeholderValue * @param int $hasBackendModel * * @dataProvider initFieldsDataProvider @@ -430,6 +441,7 @@ public function testInitFields( $configPath, $inherit, $expectedValue, + $placeholderValue, $hasBackendModel ) { // Parameters initialization @@ -499,6 +511,18 @@ public function testInitFields( $this->returnValue($configValue) ); + /** @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject $storeMock */ + $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->getMockForAbstractClass(); + $storeMock->expects($this->once()) + ->method('getCode') + ->willReturn('store_code'); + + $this->storeManagerMock->expects($this->atLeastOnce()) + ->method('getStore') + ->with('store_code') + ->willReturn($storeMock); + // Field mock configuration $fieldMock = $this->getMock( 'Magento\Config\Model\Config\Structure\Element\Field', @@ -592,17 +616,20 @@ public function testInitFields( $fieldMock->expects($this->once())->method('populateInput'); - - $settingChecker = $this->getMockBuilder(SettingChecker::class) + $settingCheckerMock = $this->getMockBuilder(SettingChecker::class) ->disableOriginalConstructor() ->getMock(); - $settingChecker->expects($this->once()) + $settingCheckerMock->expects($this->once()) ->method('isReadOnly') ->willReturn(false); - $reflection = new \ReflectionClass(get_class($this->object)); - $reflectionProperty = $reflection->getProperty('settingChecker'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->object, $settingChecker); + + $settingCheckerMock->expects($this->once()) + ->method('getPlaceholderValue') + ->willReturn($placeholderValue); + + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $helper->setBackwardCompatibleProperty($this->object, 'settingChecker', $settingCheckerMock); $this->object->initFields($fieldsetMock, $groupMock, $sectionMock, $fieldPrefix, $labelPrefix); } @@ -613,8 +640,9 @@ public function testInitFields( public function initFieldsDataProvider() { return [ - [['section1/group1/field1' => 'some_value'], false, null, false, 'some_value', 1], - [[], 'Config Value', 'some/config/path', true, 'Config Value', 0] + [['section1/group1/field1' => 'some_value'], false, null, false, 'some_value', null, 1], + [[], 'Config Value', 'some/config/path', true, 'Config Value', null, 0], + [[], 'Config Value', 'some/config/path', true, 'Placeholder Value', 'Placeholder Value', 0] ]; } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php new file mode 100644 index 0000000000000..deddafa4b3e87 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php @@ -0,0 +1,88 @@ +placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $placeholderFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->placeholderMock); + + $this->configSourceMock = $this->getMockBuilder(DumpConfigSourceInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->model = $objectManager->getObject( + Comment::class, + [ + 'placeholderFactory' => $placeholderFactoryMock, + 'source' => $this->configSourceMock + ] + ); + } + + public function testGetEmpty() + { + $this->configSourceMock->expects($this->once()) + ->method('getExcludedFields') + ->willReturn([]); + $this->assertEmpty($this->model->get()); + + } + + public function testGet() + { + $path = 'one/two'; + $placeholder = 'one__two'; + $expectedResult = 'The configuration file doesn\'t contain the sensitive data by security reason. ' + . 'The sensitive data can be stored in the next environment variables:' + . "\n$placeholder for $path"; + + $this->configSourceMock->expects($this->once()) + ->method('getExcludedFields') + ->willReturn([$path]); + + $this->placeholderMock->expects($this->once()) + ->method('generate') + ->with($path) + ->willReturn($placeholder); + + $this->assertEquals($expectedResult, $this->model->get()); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php new file mode 100644 index 0000000000000..3156ad1ec5493 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/ExcludeListTest.php @@ -0,0 +1,40 @@ +model = new ExcludeList( + [ + 'web/unsecure/base_url' => '', + 'web/test/test_value' => '0', + 'web/test/test_sensitive' => '1', + ] + ); + } + + public function testGet() + { + $this->assertEquals(['web/test/test_sensitive'], $this->model->get()); + } + + public function testIsPresent() + { + $this->assertFalse($this->model->isPresent('some/new/path')); + $this->assertFalse($this->model->isPresent('web/unsecure/base_url')); + $this->assertFalse($this->model->isPresent('web/test/test_value')); + $this->assertTrue($this->model->isPresent('web/test/test_sensitive')); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php new file mode 100644 index 0000000000000..11195dc532023 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php @@ -0,0 +1,120 @@ +placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->getMockForAbstractClass(); + + $this->placeholderFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->placeholderMock); + + $this->model = new EnvironmentPlaceholder( + $this->placeholderFactoryMock, + $this->arrayManagerMock + ); + } + + public function testProcess() + { + $_ENV = array_merge( + $_ENV, + [ + 'CONFIG_DEFAULT_TEST' => 1, + 'CONFIG_DEFAULT_TEST2' => 2, + 'BAD_CONFIG' => 3, + ] + ); + + $this->placeholderMock->expects($this->any()) + ->method('isApplicable') + ->willReturnMap( + [ + ['CONFIG_DEFAULT_TEST', true], + ['CONFIG_DEFAULT_TEST2', true], + ['BAD_CONFIG', false], + ] + ); + $this->placeholderMock->expects($this->any()) + ->method('restore') + ->willReturnMap( + [ + ['CONFIG_DEFAULT_TEST', 'default/test'], + ['CONFIG_DEFAULT_TEST2', 'default/test2'], + ] + ); + $this->arrayManagerMock->expects($this->any()) + ->method('set') + ->willReturnMap( + [ + ['default/test', [], 1, '/', ['default' => ['test' => 1]]], + [ + 'default/test2', + [ + 'default' => [ + 'test' => 1 + ] + ], + 2, + '/', + [ + 'default' => [ + 'test' => 1, + 'test2' => 2 + ] + ], + ] + ] + ); + + $this->assertSame( + [ + 'default' => [ + 'test' => 1, + 'test2' => 2 + ] + ], + $this->model->process([]) + ); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php index 2e746eae410f4..92b8c4f3e1d15 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php @@ -7,65 +7,129 @@ use Magento\Config\Model\Config\Reader; use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; -use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\Config; use Magento\Framework\App\DeploymentConfig; +use Magento\Config\Model\Placeholder\PlaceholderInterface; +use Magento\Config\Model\Placeholder\PlaceholderFactory; +use Magento\Config\Model\Placeholder\Environment; /** * Test class for checking settings that defined in config file - * - * @package Magento\Config\Test\Unit\Model\Config\Reader\Source\Deployed */ class SettingCheckerTest extends \PHPUnit_Framework_TestCase { /** * @var Config|\PHPUnit_Framework_MockObject_MockObject */ - private $config; + private $configMock; /** - * @var SettingChecker + * @var PlaceholderInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $checker; + private $placeholderMock; + + /** + * @var Config\ScopeCodeResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeCodeResolverMock; /** - * @var ScopeCodeResolver | \PHPUnit_Framework_MockObject_MockObject + * @var SettingChecker */ - private $scopeCodeResolver; + private $checker; public function setUp() { - $this->config = $this->getMockBuilder(DeploymentConfig::class) + $this->configMock = $this->getMockBuilder(DeploymentConfig::class) ->disableOriginalConstructor() ->getMock(); - $this->scopeCodeResolver = $this->getMockBuilder(ScopeCodeResolver::class) + $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->getMockForAbstractClass(); + $this->scopeCodeResolverMock = $this->getMockBuilder(Config\ScopeCodeResolver::class) ->disableOriginalConstructor() ->getMock(); - $this->checker = new SettingChecker($this->config, $this->scopeCodeResolver); + $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $placeholderFactoryMock->expects($this->once()) + ->method('create') + ->with(Environment::class) + ->willReturn($this->placeholderMock); + + $this->checker = new SettingChecker($this->configMock, $placeholderFactoryMock, $this->scopeCodeResolverMock); } - public function testIsDefined() + /** + * @param string $path + * @param string $scope + * @param string $scopeCode + * @param string|null $confValue + * @param array $variables + * @param bool $expectedResult + * @dataProvider idDefinedDataProvider + */ + public function testIsDefined($path, $scope, $scopeCode, $confValue, array $variables, $expectedResult) { - $path = 'general/web/locale'; - $scope = 'website'; - $scopeCode = 'myWebsite'; - $scopeCodeId = '4'; + $this->placeholderMock->expects($this->once()) + ->method('isApplicable') + ->willReturn(true); + $this->placeholderMock->expects($this->once()) + ->method('generate') + ->with($path, $scope, $scopeCode) + ->willReturn('SOME_PLACEHOLDER'); + $this->scopeCodeResolverMock->expects($this->any()) + ->method('resolve') + ->willReturnMap( + [ + ['website', 'myWebsite', ($scopeCode ? $scopeCode : '')] + ] + ); - $this->config->expects($this->once()) + $_ENV = array_merge($_ENV, $variables); + + $this->configMock->expects($this->any()) ->method('get') - ->willReturn([ - $scope => [ - $scopeCode => [ - $path => 'value' - ], + ->willReturnMap([ + [ + 'system/' . $scope . "/" . ($scopeCode ? $scopeCode . '/' : '') . $path, + null, + $confValue ], ]); - $this->scopeCodeResolver->expects($this->once()) - ->method('resolve') - ->with($scope, $scopeCodeId) - ->willReturn($scopeCode); + $this->assertSame($expectedResult, $this->checker->isReadOnly($path, $scope, $scopeCode)); + } - $this->assertTrue($this->checker->isReadOnly($path, $scope, $scopeCodeId)); + /** + * @return array + */ + public function idDefinedDataProvider() + { + return [ + [ + 'path' => 'general/web/locale', + 'scope' => 'website', + 'scopeCode' => 'myWebsite', + 'confValue' => 'value', + 'variables' => [], + 'expectedResult' => true, + ], + [ + 'path' => 'general/web/locale', + 'scope' => 'website', + 'scopeCode' => 'myWebsite', + 'confValue' => null, + 'variables' => ['SOME_PLACEHOLDER' => 'value'], + 'expectedResult' => true, + ], + [ + 'path' => 'general/web/locale', + 'scope' => 'website', + 'scopeCode' => 'myWebsite', + 'confValue' => null, + 'variables' => [], + 'expectedResult' => false, + ] + ]; } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php b/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php new file mode 100644 index 0000000000000..a4557503921d9 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Placeholder/EnvironmentTest.php @@ -0,0 +1,103 @@ +deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new Environment( + $this->deploymentConfigMock + ); + } + + /** + * @param string $path + * @param string $scope + * @param string $scopeId + * @param string $expected + * @dataProvider getGenerateDataProvider + */ + public function testGenerate($path, $scope, $scopeId, $expected) + { + $this->assertSame( + $this->model->generate($path, $scope, $scopeId), + $expected + ); + } + + public function getGenerateDataProvider() + { + return [ + [ + 'web/unsecure/base_url', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + Environment::PREFIX . 'DEFAULT__WEB__UNSECURE__BASE_URL' + ], + [ + 'web/unsecure/base_url', + 'web', + 'test', + Environment::PREFIX . 'WEB__TEST__WEB__UNSECURE__BASE_URL' + ], + [ + 'web/unsecure/base_url', + 'web', + null, + Environment::PREFIX . 'WEB__WEB__UNSECURE__BASE_URL' + ], + ]; + } + + /** + * @param string $placeholder + * @param bool $expected + * @dataProvider getIsPlaceholderDataProvider + */ + public function testIsApplicable($placeholder, $expected) + { + $this->assertSame( + $this->model->isApplicable($placeholder), + $expected + ); + } + + /** + * @return array + */ + public function getIsPlaceholderDataProvider() + { + return [ + [Environment::PREFIX . 'TEST', true], + ['TEST', false], + [Environment::PREFIX . 'TEST_test', true], + ]; + } +} diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index 4f9eae24b55f6..687f8609bd3ee 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -81,6 +81,7 @@ systemConfigSourceAggregatedProxy systemConfigPostProcessorCompositeProxy Magento\Framework\App\Cache\Type\Config + systemConfigPreProcessorComposite @@ -113,6 +114,13 @@ + + + + Magento\Config\Model\Config\Processor\EnvironmentPlaceholder + + + @@ -138,15 +146,15 @@ Magento\Framework\Config\File\ConfigFilePool::APP_CONFIG - + - - systemConfigInitialDataProvider - 10 - Magento\Config\App\Config\Source\RuntimeConfigSource + 100 + + + systemConfigInitialDataProvider 1000 @@ -158,8 +166,19 @@ appDumpSystemSource Magento\Config\App\Config\Type\System::CONFIG_TYPE + Magento\Config\Model\Config\Export\Comment + + + appDumpSystemSource + + + + + Magento\Config\Model\Config\Structure\Element\Iterator\Tab\Proxy + + diff --git a/app/code/Magento/Contact/etc/di.xml b/app/code/Magento/Contact/etc/di.xml new file mode 100644 index 0000000000000..95cd40cb55e31 --- /dev/null +++ b/app/code/Magento/Contact/etc/di.xml @@ -0,0 +1,16 @@ + + + + + + + 1 + + + + diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php index b4e4fef8fb2f9..40b262e3e4f51 100644 --- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php +++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php @@ -5,7 +5,7 @@ */ namespace Magento\Deploy\Console\Command\App; -use Magento\Framework\App\Config\Reader\Source\SourceInterface; +use Magento\Framework\App\Config\ConfigSourceInterface; use Magento\Framework\App\DeploymentConfig\Writer; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Console\Cli; @@ -24,7 +24,7 @@ class ApplicationDumpCommand extends Command private $writer; /** - * @var SourceInterface[] + * @var ConfigSourceInterface[] */ private $sources; @@ -64,20 +64,29 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { $dump = []; + $comments = []; foreach ($this->sources as $sourceData) { - /** @var SourceInterface $source */ + /** @var ConfigSourceInterface $source */ $source = $sourceData['source']; $namespace = $sourceData['namespace']; $dump[$namespace] = $source->get(); + if (!empty($sourceData['comment'])) { + $comments[$namespace] = is_string($sourceData['comment']) + ? $sourceData['comment'] + : $sourceData['comment']->get(); + } } - $this->writer ->saveConfig( [ConfigFilePool::APP_CONFIG => $dump], true, - ConfigFilePool::LOCAL + ConfigFilePool::LOCAL, + $comments ); + if (!empty($comments)) { + $output->writeln($comments); + } $output->writeln('Done.'); - return Cli::RETURN_SUCCESS; + return Cli::RETURN_SUCCESS; } } diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml index a7fc549a0d993..8164c48279054 100644 --- a/app/code/Magento/Developer/etc/di.xml +++ b/app/code/Magento/Developer/etc/di.xml @@ -241,4 +241,12 @@ web + + + + + 1 + + + diff --git a/app/code/Magento/Dhl/etc/di.xml b/app/code/Magento/Dhl/etc/di.xml index 25b90ce8850d8..3bc6e753344a0 100644 --- a/app/code/Magento/Dhl/etc/di.xml +++ b/app/code/Magento/Dhl/etc/di.xml @@ -13,4 +13,13 @@ + + + + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Directory/etc/di.xml b/app/code/Magento/Directory/etc/di.xml index f868197e60593..b4da40d119fe3 100644 --- a/app/code/Magento/Directory/etc/di.xml +++ b/app/code/Magento/Directory/etc/di.xml @@ -47,4 +47,12 @@ + + + + + 1 + + + diff --git a/app/code/Magento/Fedex/etc/di.xml b/app/code/Magento/Fedex/etc/di.xml index 454beffacba9d..d65a5f552bd6f 100644 --- a/app/code/Magento/Fedex/etc/di.xml +++ b/app/code/Magento/Fedex/etc/di.xml @@ -10,4 +10,14 @@ + + + + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/NewRelicReporting/etc/di.xml b/app/code/Magento/NewRelicReporting/etc/di.xml index caabf89be1871..6e3a24be91982 100644 --- a/app/code/Magento/NewRelicReporting/etc/di.xml +++ b/app/code/Magento/NewRelicReporting/etc/di.xml @@ -12,4 +12,14 @@ Magento\Framework\Module\FullModuleList + + + + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Paypal/etc/di.xml b/app/code/Magento/Paypal/etc/di.xml index 8b287d08e77a4..8c340b2ba2d85 100644 --- a/app/code/Magento/Paypal/etc/di.xml +++ b/app/code/Magento/Paypal/etc/di.xml @@ -176,4 +176,33 @@ + + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/ProductAlert/etc/di.xml b/app/code/Magento/ProductAlert/etc/di.xml index 734b0f6695778..d5c81adce46f0 100644 --- a/app/code/Magento/ProductAlert/etc/di.xml +++ b/app/code/Magento/ProductAlert/etc/di.xml @@ -13,4 +13,12 @@ + + + + + 1 + + + diff --git a/app/code/Magento/ProductVideo/etc/di.xml b/app/code/Magento/ProductVideo/etc/di.xml index 09c15d8fccecc..0fcacfdcefc6c 100644 --- a/app/code/Magento/ProductVideo/etc/di.xml +++ b/app/code/Magento/ProductVideo/etc/di.xml @@ -45,4 +45,11 @@ + + + + 1 + + + diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index 50520fdcb311a..32bb86cd70cf1 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -954,4 +954,18 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Shipping/etc/di.xml b/app/code/Magento/Shipping/etc/di.xml index 1fe0657bf1337..44e138d6c9ac6 100644 --- a/app/code/Magento/Shipping/etc/di.xml +++ b/app/code/Magento/Shipping/etc/di.xml @@ -9,4 +9,16 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Sitemap/etc/di.xml b/app/code/Magento/Sitemap/etc/di.xml index 7ce1fdee7b5b6..dfe34a25fb7ba 100644 --- a/app/code/Magento/Sitemap/etc/di.xml +++ b/app/code/Magento/Sitemap/etc/di.xml @@ -11,4 +11,11 @@ Magento\Sitemap\Model\ResourceModel\Sitemap + + + + 1 + + + diff --git a/app/code/Magento/Ups/etc/di.xml b/app/code/Magento/Ups/etc/di.xml new file mode 100644 index 0000000000000..324349a82994f --- /dev/null +++ b/app/code/Magento/Ups/etc/di.xml @@ -0,0 +1,21 @@ + + + + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + + diff --git a/app/code/Magento/Usps/etc/di.xml b/app/code/Magento/Usps/etc/di.xml new file mode 100644 index 0000000000000..450a24ad8b9f7 --- /dev/null +++ b/app/code/Magento/Usps/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + + 1 + 1 + 1 + 1 + + + + diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php new file mode 100644 index 0000000000000..1e2b6aacc9314 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Processor/EnvironmentPlaceholderTest.php @@ -0,0 +1,103 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->get(EnvironmentPlaceholder::class); + $this->env = $_ENV; + } + + public function testProcess() + { + $_ENV = array_merge( + $_ENV, + [ + 'CONFIG__DEFAULT__WEB__UNSECURE__BASE_URL' => 'http://expected.local', + 'CONFIG__TEST__TEST__DESIGN__HEADER__WELCOME' => 'Expected header', + 'TEST__TEST__WEB__SECURE__BASE_URL' => 'http://wrong_pattern.local', + 'CONFIG__DEFAULT__GENERAL__REGION__DISPLAY_ALL' => 1 + ] + ); + $expected = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://expected.local' + ], + 'secure' => [ + 'base_url' => 'https://original.local' + ] + ], + 'general' => [ + 'region' => [ + 'display_all' => 1 + ], + ], + ], + 'test' => [ + 'test' => [ + 'design' => [ + 'header' => [ + 'welcome' => 'Expected header' + ] + ], + ], + ] + ]; + $config = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://original.local', + ], + 'secure' => [ + 'base_url' => 'https://original.local' + ] + ] + ], + 'test' => [ + 'test' => [ + 'design' => [ + 'header' => [ + 'welcome' => 'Original header' + ] + ], + ], + ] + ]; + + $this->assertSame( + $expected, + $this->model->process($config) + ); + } + + protected function tearDown() + { + $_ENV = $this->env; + } +} 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 a229b64bb7dd1..aafba9c159ba2 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 @@ -7,7 +7,6 @@ use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Filesystem\DriverPool; use Magento\Framework\ObjectManagerInterface; @@ -18,37 +17,73 @@ class ApplicationDumpCommandTest extends \PHPUnit_Framework_TestCase { /** - * @var ApplicationDumpCommand + * @var ObjectManagerInterface */ - private $command; + private $objectManager; /** - * @var ObjectManagerInterface + * @var DeploymentConfig\Reader */ - private $objectManager; + private $reader; public function setUp() { - $this->command = Bootstrap::getObjectManager()->get(ApplicationDumpCommand::class); $this->objectManager = Bootstrap::getObjectManager(); + $this->reader = $this->objectManager->get(DeploymentConfig\Reader::class); } + /** + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Deploy/_files/config_data.php + */ public function testExecute() { - $inputMock = $this->getMock(InputInterface::class); + $this->objectManager->configure([ + \Magento\Config\Model\Config\Export\ExcludeList::class => [ + 'arguments' => [ + 'configs' => [ + 'web/test/test_value_1' => '', + 'web/test/test_value_2' => '', + 'web/test/test_sensitive' => '1', + ], + ], + ], + ]); + + $comment = 'The configuration file doesn\'t contain the sensitive data by security reason. ' + . 'The sensitive data can be stored in the next environment variables:' + . "\nCONFIG__DEFAULT__WEB__TEST__TEST_SENSITIVE for web/test/test_sensitive"; $outputMock = $this->getMock(OutputInterface::class); - $outputMock->expects($this->once()) + $outputMock->expects($this->at(0)) + ->method('writeln') + ->with(['system' => $comment]); + $outputMock->expects($this->at(1)) ->method('writeln') ->with('Done.'); - $this->assertEquals(0, $this->command->run($inputMock, $outputMock)); + + /** @var ApplicationDumpCommand command */ + $command = $this->objectManager->create(ApplicationDumpCommand::class); + $command->run($this->getMock(InputInterface::class), $outputMock); + + $config = $this->reader->loadConfigFile(ConfigFilePool::APP_CONFIG, $this->getFileName()); + + $this->assertArrayHasKey( + 'test_value_1', + $config['system']['default']['web']['test'] + ); + $this->assertArrayHasKey( + 'test_value_2', + $config['system']['default']['web']['test'] + ); + $this->assertArrayNotHasKey( + 'test_sensitive', + $config['system']['default']['web']['test'] + ); } public function tearDown() { - /** @var ConfigFilePool $configFilePool */ - $configFilePool = $this->objectManager->get(ConfigFilePool::class); - $filePool = $configFilePool->getInitialFilePools(); - $file = $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG]; + $file = $this->getFileName(); /** @var DirectoryList $dirList */ $dirList = $this->objectManager->get(DirectoryList::class); $path = $dirList->getPath(DirectoryList::CONFIG); @@ -61,4 +96,16 @@ public function tearDown() $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]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php new file mode 100644 index 0000000000000..bd8e69262e1e0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php @@ -0,0 +1,33 @@ + [ + '' => [ + 'web/test/test_value_1' => 'http://local2.test/', + 'web/test/test_value_2' => 5, + 'web/test/test_sensitive' => 10, + ] + ], +]; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$configFactory = $objectManager->create(\Magento\Config\Model\Config\Factory::class); + +foreach ($configData as $scope => $data) { + foreach ($data as $scopeCode => $scopeData) { + foreach ($scopeData as $path => $value) { + $config = $configFactory->create(); + $config->setCope($scope); + + if ($scopeCode) { + $config->setScopeCode($scopeCode); + } + + $config->setDataByPath($path, $value); + $config->save(); + } + } +} diff --git a/lib/internal/Magento/Framework/App/Config.php b/lib/internal/Magento/Framework/App/Config.php index 7cc78b8f22457..c817949858d67 100644 --- a/lib/internal/Magento/Framework/App/Config.php +++ b/lib/internal/Magento/Framework/App/Config.php @@ -137,7 +137,7 @@ public function get($configType, $path = '', $default = null) if (isset($this->types[$configType])) { $result = $this->types[$configType]->get($path); } - + return $result !== null ? $result : $default; } } diff --git a/lib/internal/Magento/Framework/App/Config/CommentInterface.php b/lib/internal/Magento/Framework/App/Config/CommentInterface.php new file mode 100644 index 0000000000000..902d63668f368 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/CommentInterface.php @@ -0,0 +1,21 @@ +processors = $processors; + } + + /** + * @inheritdoc + */ + public function process(array $config) + { + /** @var PreProcessorInterface $processor */ + foreach ($this->processors as $processor) { + $config = $processor->process($config); + } + + return $config; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php b/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php new file mode 100644 index 0000000000000..1be0783d7f7de --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/Spi/PreProcessorInterface.php @@ -0,0 +1,20 @@ +dirList->getPath(DirectoryList::CONFIG); $fileDriver = $this->driverPool->getDriver(DriverPool::FILE); - if ($fileDriver->isExists($path . '/' . $pathConfig)) { - $result = include $path . '/' . $pathConfig; - $result = is_array($result) ? $result : []; - } - if (!$ignoreInitialConfigFiles) { foreach ($initialFilePools as $initialFiles) { if (isset($initialFiles[$fileKey]) && $fileDriver->isExists($path . '/' . $initialFiles[$fileKey])) { $fileBuffer = include $path . '/' . $initialFiles[$fileKey]; - $result = array_replace_recursive($result, $fileBuffer); + if (is_array($fileBuffer)) { + $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; } diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php index 6cead0305a6c6..2d8e7a14aaf55 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php @@ -94,10 +94,11 @@ public function checkIfWritable() * @param array $data * @param bool $override * @param string $pool + * @param array $comments * @return void * @throws FileSystemException */ - public function saveConfig(array $data, $override = false, $pool = null) + 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(); @@ -112,7 +113,7 @@ public function saveConfig(array $data, $override = false, $pool = null) } } - $contents = $this->formatter->format($config); + $contents = $this->formatter->format($config, $comments); try { $writeFilePath = $paths[$fileKey]; $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile($writeFilePath, $contents); diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php index 24e31074501f3..640bcb61d2031 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php @@ -12,7 +12,8 @@ interface FormatterInterface * Format deployment configuration * * @param array $data + * @param array $comments * @return string */ - public function format($data); + public function format($data, array $comments = []); } diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php index 1ab99358cef1a..56c8c072357e6 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php @@ -14,8 +14,20 @@ class PhpFormatter implements FormatterInterface /** * {@inheritdoc} */ - public function format($data) + public function format($data, array $comments = []) { + if (!empty($comments) && is_array($data)) { + $elements = array(); + foreach ($data as $key => $value) { + $comment = ' '; + if (!empty($comments[$key])) { + $comment = " /**\n * " . str_replace("\n", "\n * ", var_export($comments[$key], true)) . "\n */\n"; + } + $space = is_array($value) ? " \n" : ' '; + $elements[] = $comment . var_export($key, true) . ' =>' . $space . var_export($value, true); + } + return "preProcessorMock = $this->getMockBuilder(PreProcessorInterface::class) + ->getMockForAbstractClass(); + + $this->model = new PreProcessorComposite([$this->preProcessorMock]); + } + + public function testProcess() + { + $this->preProcessorMock->expects($this->once()) + ->method('process') + ->with(['test' => 'data']) + ->willReturn(['test' => 'data2']); + + $this->assertSame(['test' => 'data2'], $this->model->process(['test' => 'data'])); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php index a9b5bc04a1276..1815658d13544 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php @@ -10,10 +10,125 @@ class PhpFormatterTest extends \PHPUnit_Framework_TestCase { - public function testFormat() + /** + * @dataProvider formatWithCommentDataProvider + * @param string|array $data + * @param array $comments + * @param string $expectedResult + */ + public function testFormat($data, $comments, $expectedResult) { $formatter = new PhpFormatter(); - $data = 'test'; - $this->assertEquals("format($data)); + $this->assertEquals($expectedResult, $formatter->format($data, $comments)); + } + + public function formatWithCommentDataProvider() + { + $array = [ + 'ns1' => [ + 's1' => [ + 's11', + 's12' + ], + 's2' => [ + 's21', + 's22' + ], + ], + 'ns2' => [ + 's1' => [ + 's11' + ], + ], + 'ns3' => 'just text', + 'ns4' => 'just text' + ]; + $comments1 = ['ns2' => 'comment for namespace 2']; + $comments2 = [ + 'ns1' => 'comment for namespace 1', + 'ns2' => "comment for namespace 2.\nNext comment for namespace 2", + 'ns3' => 'comment for namespace 3', + 'ns4' => 'comment for namespace 4', + 'ns5' => 'comment for unexisted namespace 5', + ]; + $expectedResult1 = << + array ( + 's1' => + array ( + 0 => 's11', + 1 => 's12', + ), + 's2' => + array ( + 0 => 's21', + 1 => 's22', + ), + ), + /** + * 'comment for namespace 2' + */ + 'ns2' => + array ( + 's1' => + array ( + 0 => 's11', + ), + ), + 'ns3' => 'just text', + 'ns4' => 'just text' +); + +TEXT; + $expectedResult2 = << + array ( + 's1' => + array ( + 0 => 's11', + 1 => 's12', + ), + 's2' => + array ( + 0 => 's21', + 1 => 's22', + ), + ), + /** + * 'comment for namespace 2. + * Next comment for namespace 2' + */ + 'ns2' => + array ( + 's1' => + array ( + 0 => 's11', + ), + ), + /** + * 'comment for namespace 3' + */ + 'ns3' => 'just text', + /** + * 'comment for namespace 4' + */ + 'ns4' => 'just text' +); + +TEXT; + return [ + ['string', [], " Date: Wed, 2 Nov 2016 11:13:10 +0200 Subject: [PATCH 2/8] MAGETWO-60355: [Backport] - Production mode cannot be enabled - for 2.1 --- .../ObjectManager/Config/Compiled.php | 12 ++- .../Test/Unit/Config/CompiledTest.php | 91 +++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php diff --git a/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php b/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php index 227b9444b6061..d155432894daf 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php +++ b/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php @@ -129,9 +129,15 @@ public function getPreference($type) */ public function extend(array $configuration) { - $this->arguments = $configuration['arguments']; - $this->virtualTypes = $configuration['instanceTypes']; - $this->preferences = $configuration['preferences']; + $this->arguments = isset($configuration['arguments']) + ? array_replace($this->arguments, $configuration['arguments']) + : $this->arguments; + $this->virtualTypes = isset($configuration['instanceTypes']) + ? array_replace($this->virtualTypes, $configuration['instanceTypes']) + : $this->virtualTypes; + $this->preferences = isset($configuration['preferences']) + ? array_replace($this->preferences, $configuration['preferences']) + : $this->preferences; } /** diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php new file mode 100644 index 0000000000000..1fcf3176540db --- /dev/null +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php @@ -0,0 +1,91 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @param array $initialData + * @param array $configuration + * @param array $expectedArguments + * @param array $expectedVirtualTypes + * @param array $expectedPreferences + * + * @dataProvider extendDataProvider + */ + public function testExtend( + array $initialData, + array $configuration, + array $expectedArguments, + array $expectedVirtualTypes, + array $expectedPreferences + ) { + /** @var CompiledConfig $compiledConfig */ + $compiledConfig = $this->objectManagerHelper->getObject(CompiledConfig::class, ['data' => $initialData]); + $compiledConfig->extend($configuration); + + foreach ($expectedArguments as $type => $arguments) { + $this->assertEquals($arguments, $compiledConfig->getArguments($type)); + } + + $this->assertEquals($expectedVirtualTypes, $compiledConfig->getVirtualTypes()); + $this->assertEquals($expectedPreferences, $compiledConfig->getPreferences()); + } + + /** + * @return array + */ + public function extendDataProvider() + { + return [ + [ + 'initialData' => [ + 'arguments' => [ + 'type1' => serialize(['argument1_1' => 'argumentValue1_1', 'argument1_2' => 'argumentValue1_2']) + ], + 'instanceTypes' => [ + 'instanceType1' => 'instanceTypeValue1', 'instanceType2' => 'instanceTypeValue2' + ], + 'preferences' => ['preference1' => 'preferenceValue1', 'preference2' => 'preferenceValue2'] + ], + 'configuration' => [ + 'arguments' => [ + 'type1' => serialize(['argument1_1' => 'newArgumentValue1_1']), + 'type2' => serialize(['argument2_1' => 'newArgumentValue2_1']) + ], + 'instanceTypes' => [ + 'instanceType2' => 'newInstanceTypeValue2', 'instanceType3' => 'newInstanceTypeValue3' + ], + 'preferences' => ['preference1' => 'newPreferenceValue1'] + ], + 'expectedArguments' => [ + 'type1' => ['argument1_1' => 'newArgumentValue1_1'], + 'type2' => ['argument2_1' => 'newArgumentValue2_1'] + ], + 'expectedVirtualTypes' => [ + 'instanceType1' => 'instanceTypeValue1', 'instanceType2' => 'newInstanceTypeValue2', + 'instanceType3' => 'newInstanceTypeValue3' + ], + 'expectedPreferences' => [ + 'preference1' => 'newPreferenceValue1', 'preference2' => 'preferenceValue2' + ] + ] + ]; + } +} From 8468dc39d09b526cf05ac1903e05f2edf235e378 Mon Sep 17 00:00:00 2001 From: Oleksandr Shmyheliuk Date: Wed, 2 Nov 2016 14:47:30 +0200 Subject: [PATCH 3/8] MAGETWO-60381: Disable fields functionality doesn't work for theme configuration --- .../Model/Design/Config/DataProvider.php | 119 +++++++++++++ .../Model/Design/Config/DataProviderTest.php | 157 ++++++++++++++++++ 2 files changed, 276 insertions(+) diff --git a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php index c433b02fab240..ce91a3a85a484 100644 --- a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php +++ b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php @@ -5,9 +5,13 @@ */ namespace Magento\Theme\Model\Design\Config; +use Magento\Framework\App\ObjectManager; +use Magento\Store\Model\StoreManagerInterface; use Magento\Theme\Model\ResourceModel\Design\Config\Collection; use Magento\Theme\Model\ResourceModel\Design\Config\CollectionFactory; use Magento\Ui\DataProvider\AbstractDataProvider; +use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\RequestInterface; class DataProvider extends AbstractDataProvider { @@ -31,6 +35,21 @@ class DataProvider extends AbstractDataProvider */ private $metadataLoader; + /** + * @var SettingChecker + */ + private $settingChecker; + + /** + * @var RequestInterface + */ + private $request; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * @param string $name * @param string $primaryFieldName @@ -78,4 +97,104 @@ public function getData() $this->loadedData = $this->dataLoader->getData(); return $this->loadedData; } + + /** + * {@inheritdoc} + */ + public function getMeta() + { + $meta = parent::getMeta(); + if (!isset($meta['other_settings']['children'])) { + return $meta; + } + + $request = $this->getRequest()->getParams(); + if (!isset($request['scope'])) { + return $meta; + } + + $scope = $request['scope']; + $scopeCode = $this->getStringScopeCode( + $scope, + isset($request['scope_id']) ? $request['scope_id'] : null + ); + + foreach ($meta['other_settings']['children'] as $settingGroupName => &$settingGroup) { + foreach ($settingGroup['children'] as $fieldName => &$field) { + $path = sprintf( + 'design/%s/%s', + $settingGroupName, + preg_replace('/^' . $settingGroupName . '_/', '', $fieldName) + ); + $isReadOnly = $this->getSettingChecker()->isReadOnly( + $path, + $scope, + $scopeCode + ); + + if ($isReadOnly) { + $field['arguments']['data']['config']['disabled'] = true; + $field['arguments']['data']['config']['is_disable_inheritance'] = true; + } + } + } + + return $meta; + } + + /** + * Retrieve Scope string code + * + * @param string $scope + * @param integer $scopeId + * @return string + */ + private function getStringScopeCode($scope, $scopeId = null) + { + $scopeCode = ''; + + if ($scope == 'stores') { + $scopeCode = $this->getStoreManager()->getStore($scopeId)->getCode(); + } elseif ($scope == 'websites') { + $scopeCode = $this->getStoreManager()->getWebsite($scopeId)->getCode(); + } + + return $scopeCode; + } + + /** + * @deprecated + * @return SettingChecker + */ + private function getSettingChecker() + { + if ($this->settingChecker === null) { + $this->settingChecker = ObjectManager::getInstance()->get(SettingChecker::class); + } + return $this->settingChecker; + } + + /** + * @deprecated + * @return RequestInterface + */ + private function getRequest() + { + if ($this->request === null) { + $this->request = ObjectManager::getInstance()->get(RequestInterface::class); + } + return $this->request; + } + + /** + * @deprecated + * @return StoreManagerInterface + */ + private function getStoreManager() + { + if ($this->storeManager === null) { + $this->storeManager = ObjectManager::getInstance()->get(StoreManagerInterface::class); + } + return $this->storeManager; + } } diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php index 2d90748b59576..d75df7d0f188b 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php @@ -5,6 +5,11 @@ */ namespace Magento\Theme\Test\Unit\Model\Design\Config; +use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; use Magento\Theme\Model\Design\Config\DataLoader; use Magento\Theme\Model\Design\Config\DataProvider; use Magento\Theme\Model\Design\Config\MetadataLoader; @@ -32,8 +37,29 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase */ protected $collection; + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManagerMock; + + /** + * @var SettingChecker|\PHPUnit_Framework_MockObject_MockObject + */ + private $settingCheckerMock; + protected function setUp() { + $this->objectManager = new ObjectManager($this); $this->dataLoader = $this->getMockBuilder('Magento\Theme\Model\Design\Config\DataProvider\DataLoader') ->disableOriginalConstructor() ->getMock(); @@ -57,6 +83,16 @@ protected function setUp() ->method('create') ->willReturn($this->collection); + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->settingCheckerMock = $this->getMockBuilder(SettingChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model = new DataProvider( 'scope', 'scope', @@ -65,6 +101,21 @@ protected function setUp() $this->metadataLoader, $collectionFactory ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'request', + $this->requestMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'storeManager', + $this->storeManagerMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'settingChecker', + $this->settingCheckerMock + ); } public function testGetData() @@ -79,4 +130,110 @@ public function testGetData() $this->assertEquals($data, $this->model->getData()); } + + /** + * @param array $inputMeta + * @param array $expectedMeta + * @param array $request + * @dataProvider getMetaDataProvider + */ + public function testGetMeta(array $inputMeta, array $expectedMeta, array $request) + { + $store = $this->getMockBuilder(StoreInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $store->expects($this->any()) + ->method('getCode') + ->willReturn('store1'); + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn($request); + $this->storeManagerMock->expects($this->any()) + ->method('getStore') + ->with(1) + ->willReturn($store); + $this->settingCheckerMock->expects($this->any()) + ->method('isReadOnly') + ->withConsecutive( + ['design/head/welcome', 'stores', 'store1'], + ['design/head/logo', 'stores', 'store1'] + ) + ->willReturnOnConsecutiveCalls( + true, + false + ); + + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'meta', + $inputMeta + ); + + $this->assertSame($expectedMeta, $this->model->getMeta()); + } + + /** + * @return array + */ + public function getMetaDataProvider() + { + return [ + [ + [ + 'option1' + ], + [ + 'option1' + ], + [ + 'scope' => 'default' + ] + ], + [ + [ + 'other_settings' => [ + 'children' => [ + 'head' => [ + 'children' => [ + 'head_welcome' => [ + + ], + 'head_logo' => [ + + ] + ] + ] + ] + ] + ], + [ + 'other_settings' => [ + 'children' => [ + 'head' => [ + 'children' => [ + 'head_welcome' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'disabled' => true, + 'is_disable_inheritance' => true, + ] + ] + ] + ], + 'head_logo' => [ + + ] + ] + ] + ] + ] + ], + [ + 'scope' => 'stores', + 'scope_id' => 1 + ] + ] + ]; + } } From a9e80c13909a07eed74135933b1a396a1fbdb1eb Mon Sep 17 00:00:00 2001 From: Oleh Posyniak Date: Wed, 2 Nov 2016 15:20:55 +0200 Subject: [PATCH 4/8] MAGETWO-59809: Scrub sensitive data during app:dump --- .../Source/DumpConfigSourceAggregated.php | 3 +- .../Config/Block/System/Config/Form.php | 4 +- .../Reader/Source/Deployed/SettingChecker.php | 16 ++++--- .../Config/Model/Placeholder/Environment.php | 7 ++- .../Source/DumpConfigSourceAggregatedTest.php | 46 +++++++++++++++++++ .../Processor/EnvironmentPlaceholderTest.php | 13 +++++- .../Source/Deployed/SettingCheckerTest.php | 20 ++++++-- .../DeploymentConfig/Writer/PhpFormatter.php | 4 ++ 8 files changed, 98 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php index 41196b78567b9..f8dfe1f5b5802 100644 --- a/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php +++ b/app/code/Magento/Config/App/Config/Source/DumpConfigSourceAggregated.php @@ -75,6 +75,7 @@ public function get($path = '') * * @param string $path * @param array $data + * @return void */ private function filterChain($path, &$data) { @@ -121,7 +122,7 @@ private function filterPath($path) } /** - * Sort sources + * Sort sources ASC from higher priority to lower * * @return void */ diff --git a/app/code/Magento/Config/Block/System/Config/Form.php b/app/code/Magento/Config/Block/System/Config/Form.php index 3ba73379143a1..3522ff27504a4 100644 --- a/app/code/Magento/Config/Block/System/Config/Form.php +++ b/app/code/Magento/Config/Block/System/Config/Form.php @@ -431,6 +431,7 @@ protected function _initElement( private function getStringScopeCode() { $scopeCode = $this->getData('scope_string_code'); + if (null === $scopeCode) { if ($this->getStoreCode()) { $scopeCode = $this->_storeManager->getStore($this->getStoreCode())->getCode(); @@ -439,7 +440,8 @@ private function getStringScopeCode() } else { $scopeCode = ''; } - $this->setScopeStringCode($scopeCode); + + $this->setData('scope_string_code', $scopeCode); } return $scopeCode; diff --git a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php index b1fe859fcadc4..13daa9725d60d 100644 --- a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php +++ b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php @@ -64,10 +64,13 @@ public function __construct( public function isReadOnly($path, $scope, $scopeCode = null) { $config = $this->getEnvValue( - $this->placeholder->generate($path, $scope, $scopeCode), - $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path) + $this->placeholder->generate($path, $scope, $scopeCode) ); + if (null === $config) { + $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path); + } + return $config !== null; } @@ -79,7 +82,7 @@ public function isReadOnly($path, $scope, $scopeCode = null) * @param string $path * @param string $scope * @param string|null $scopeCode - * @return mixed + * @return string|null */ public function getPlaceholderValue($path, $scope, $scopeCode = null) { @@ -90,10 +93,9 @@ public function getPlaceholderValue($path, $scope, $scopeCode = null) * Retrieve value of environment variable by placeholder * * @param string $placeholder - * @param mixed $defaultValue - * @return mixed + * @return string|null */ - public function getEnvValue($placeholder, $defaultValue = null) + public function getEnvValue($placeholder) { if (null === $this->environmentVariables) { $this->environmentVariables = $_ENV; @@ -103,7 +105,7 @@ public function getEnvValue($placeholder, $defaultValue = null) return $this->environmentVariables[$placeholder]; } - return $defaultValue; + return null; } diff --git a/app/code/Magento/Config/Model/Placeholder/Environment.php b/app/code/Magento/Config/Model/Placeholder/Environment.php index aacc049e60799..961a29e7b2493 100644 --- a/app/code/Magento/Config/Model/Placeholder/Environment.php +++ b/app/code/Magento/Config/Model/Placeholder/Environment.php @@ -9,10 +9,13 @@ use Magento\Framework\App\DeploymentConfig; /** - * Class Environment + * Class is used to work with placeholders for environment variables names based on config paths */ class Environment implements PlaceholderInterface { + /** + * @const string Prefix for placeholder + */ const PREFIX = 'CONFIG__'; /** @@ -29,6 +32,8 @@ public function __construct(DeploymentConfig $deploymentConfig) } /** + * Generates placeholder like CONFIG__DEFAULT__TEST__TEST_VALUE + * * @inheritdoc */ public function generate($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php index 32ace42ff7c26..9c6aef37540e5 100644 --- a/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php +++ b/app/code/Magento/Config/Test/Unit/App/Config/Source/DumpConfigSourceAggregatedTest.php @@ -122,4 +122,50 @@ public function testGet() ); } + public function testGetExcludedFields() + { + $path = ''; + $data = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [ + 'base_url' => 'https://test.local', + ] + ] + ], + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ] + ] + ]; + + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn($data); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->excludeListMock->expects($this->any()) + ->method('isPresent') + ->willReturnMap([ + ['web/unsecure/base_url', false], + ['web/secure/base_url', true], + ['test1/test2/test/3', false] + ]); + + $this->assertEquals( + ['web/secure/base_url'], + $this->model->getExcludedFields() + ); + } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php index 11195dc532023..71c1a6bdda425 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php @@ -34,6 +34,11 @@ class EnvironmentPlaceholderTest extends \PHPUnit_Framework_TestCase */ private $placeholderMock; + /** + * @var array + */ + private $env; + protected function setUp() { $this->placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) @@ -44,6 +49,7 @@ protected function setUp() ->getMock(); $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) ->getMockForAbstractClass(); + $this->env = $_ENV; $this->placeholderFactoryMock->expects($this->any()) ->method('create') @@ -58,7 +64,7 @@ protected function setUp() public function testProcess() { $_ENV = array_merge( - $_ENV, + $this->env, [ 'CONFIG_DEFAULT_TEST' => 1, 'CONFIG_DEFAULT_TEST2' => 2, @@ -117,4 +123,9 @@ public function testProcess() $this->model->process([]) ); } + + protected function tearDown() + { + $_ENV = $this->env; + } } diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php index 92b8c4f3e1d15..4b28b8f2b27c9 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php @@ -38,6 +38,11 @@ class SettingCheckerTest extends \PHPUnit_Framework_TestCase */ private $checker; + /** + * @var array + */ + private $env; + public function setUp() { $this->configMock = $this->getMockBuilder(DeploymentConfig::class) @@ -51,6 +56,8 @@ public function setUp() $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) ->disableOriginalConstructor() ->getMock(); + $this->env = $_ENV; + $placeholderFactoryMock->expects($this->once()) ->method('create') ->with(Environment::class) @@ -66,9 +73,9 @@ public function setUp() * @param string|null $confValue * @param array $variables * @param bool $expectedResult - * @dataProvider idDefinedDataProvider + * @dataProvider isReadonlyDataProvider */ - public function testIsDefined($path, $scope, $scopeCode, $confValue, array $variables, $expectedResult) + public function testIsReadonly($path, $scope, $scopeCode, $confValue, array $variables, $expectedResult) { $this->placeholderMock->expects($this->once()) ->method('isApplicable') @@ -85,7 +92,7 @@ public function testIsDefined($path, $scope, $scopeCode, $confValue, array $vari ] ); - $_ENV = array_merge($_ENV, $variables); + $_ENV = array_merge($this->env, $variables); $this->configMock->expects($this->any()) ->method('get') @@ -103,7 +110,7 @@ public function testIsDefined($path, $scope, $scopeCode, $confValue, array $vari /** * @return array */ - public function idDefinedDataProvider() + public function isReadonlyDataProvider() { return [ [ @@ -132,4 +139,9 @@ public function idDefinedDataProvider() ] ]; } + + protected function tearDown() + { + $_ENV = $this->env; + } } diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php index 56c8c072357e6..ecab03c95e4a7 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php @@ -12,6 +12,10 @@ class PhpFormatter implements FormatterInterface { /** + * Format deployment configuration. + * If $comments is present, each item will be added + * as comment to the corresponding section + * * {@inheritdoc} */ public function format($data, array $comments = []) From fcb1512ee0270d3a0e18a492c10eb112c0e6a420 Mon Sep 17 00:00:00 2001 From: Oleksandr Shmyheliuk Date: Wed, 2 Nov 2016 16:04:55 +0200 Subject: [PATCH 5/8] MAGETWO-60381: Disable fields functionality doesn't work for theme configuration --- .../Model/Design/Config/DataProvider.php | 40 +++++-------------- .../Model/Design/Config/DataProviderTest.php | 31 ++++++-------- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php index ce91a3a85a484..977295c1f80c4 100644 --- a/app/code/Magento/Theme/Model/Design/Config/DataProvider.php +++ b/app/code/Magento/Theme/Model/Design/Config/DataProvider.php @@ -5,8 +5,8 @@ */ namespace Magento\Theme\Model\Design\Config; +use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\ObjectManager; -use Magento\Store\Model\StoreManagerInterface; use Magento\Theme\Model\ResourceModel\Design\Config\Collection; use Magento\Theme\Model\ResourceModel\Design\Config\CollectionFactory; use Magento\Ui\DataProvider\AbstractDataProvider; @@ -46,9 +46,9 @@ class DataProvider extends AbstractDataProvider private $request; /** - * @var StoreManagerInterface + * @var ScopeCodeResolver */ - private $storeManager; + private $scopeCodeResolver; /** * @param string $name @@ -114,7 +114,7 @@ public function getMeta() } $scope = $request['scope']; - $scopeCode = $this->getStringScopeCode( + $scopeCode = $this->getScopeCodeResolver()->resolve( $scope, isset($request['scope_id']) ? $request['scope_id'] : null ); @@ -143,23 +143,15 @@ public function getMeta() } /** - * Retrieve Scope string code - * - * @param string $scope - * @param integer $scopeId - * @return string + * @deprecated + * @return ScopeCodeResolver */ - private function getStringScopeCode($scope, $scopeId = null) + private function getScopeCodeResolver() { - $scopeCode = ''; - - if ($scope == 'stores') { - $scopeCode = $this->getStoreManager()->getStore($scopeId)->getCode(); - } elseif ($scope == 'websites') { - $scopeCode = $this->getStoreManager()->getWebsite($scopeId)->getCode(); + if ($this->scopeCodeResolver === null) { + $this->scopeCodeResolver = ObjectManager::getInstance()->get(ScopeCodeResolver::class); } - - return $scopeCode; + return $this->scopeCodeResolver; } /** @@ -185,16 +177,4 @@ private function getRequest() } return $this->request; } - - /** - * @deprecated - * @return StoreManagerInterface - */ - private function getStoreManager() - { - if ($this->storeManager === null) { - $this->storeManager = ObjectManager::getInstance()->get(StoreManagerInterface::class); - } - return $this->storeManager; - } } diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php index d75df7d0f188b..f14cd139b9d43 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php @@ -6,10 +6,9 @@ namespace Magento\Theme\Test\Unit\Model\Design\Config; use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; +use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\RequestInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\StoreManagerInterface; use Magento\Theme\Model\Design\Config\DataLoader; use Magento\Theme\Model\Design\Config\DataProvider; use Magento\Theme\Model\Design\Config\MetadataLoader; @@ -48,9 +47,9 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase private $requestMock; /** - * @var StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ScopeCodeResolver|\PHPUnit_Framework_MockObject_MockObject */ - private $storeManagerMock; + private $scopeCodeResolverMock; /** * @var SettingChecker|\PHPUnit_Framework_MockObject_MockObject @@ -86,7 +85,7 @@ protected function setUp() $this->requestMock = $this->getMockBuilder(RequestInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + $this->scopeCodeResolverMock = $this->getMockBuilder(ScopeCodeResolver::class) ->disableOriginalConstructor() ->getMock(); $this->settingCheckerMock = $this->getMockBuilder(SettingChecker::class) @@ -108,8 +107,8 @@ protected function setUp() ); $this->objectManager->setBackwardCompatibleProperty( $this->model, - 'storeManager', - $this->storeManagerMock + 'scopeCodeResolver', + $this->scopeCodeResolverMock ); $this->objectManager->setBackwardCompatibleProperty( $this->model, @@ -139,24 +138,18 @@ public function testGetData() */ public function testGetMeta(array $inputMeta, array $expectedMeta, array $request) { - $store = $this->getMockBuilder(StoreInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $store->expects($this->any()) - ->method('getCode') - ->willReturn('store1'); $this->requestMock->expects($this->any()) ->method('getParams') ->willReturn($request); - $this->storeManagerMock->expects($this->any()) - ->method('getStore') - ->with(1) - ->willReturn($store); + $this->scopeCodeResolverMock->expects($this->any()) + ->method('resolve') + ->with('stores', 1) + ->willReturn('default'); $this->settingCheckerMock->expects($this->any()) ->method('isReadOnly') ->withConsecutive( - ['design/head/welcome', 'stores', 'store1'], - ['design/head/logo', 'stores', 'store1'] + ['design/head/welcome', 'stores', 'default'], + ['design/head/logo', 'stores', 'default'] ) ->willReturnOnConsecutiveCalls( true, From 24d38d30e2f52cadd636759d89aef45516c60a90 Mon Sep 17 00:00:00 2001 From: Oleksandr Shmyheliuk Date: Wed, 2 Nov 2016 16:48:35 +0200 Subject: [PATCH 6/8] MAGETWO-60381: Disable fields functionality doesn't work for theme configuration --- .../Model/Design/Config/DataProviderTest.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php index f14cd139b9d43..fd397a8ad4933 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/DataProviderTest.php @@ -149,11 +149,13 @@ public function testGetMeta(array $inputMeta, array $expectedMeta, array $reques ->method('isReadOnly') ->withConsecutive( ['design/head/welcome', 'stores', 'default'], - ['design/head/logo', 'stores', 'default'] + ['design/head/logo', 'stores', 'default'], + ['design/head/head', 'stores', 'default'] ) ->willReturnOnConsecutiveCalls( true, - false + false, + true ); $this->objectManager->setBackwardCompatibleProperty( @@ -193,6 +195,9 @@ public function getMetaDataProvider() ], 'head_logo' => [ + ], + 'head_head' => [ + ] ] ] @@ -216,6 +221,16 @@ public function getMetaDataProvider() ], 'head_logo' => [ + ], + 'head_head' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'disabled' => true, + 'is_disable_inheritance' => true, + ] + ] + ] ] ] ] From c893f1690261d9a46076d6ff29a88bad1839408c Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 2 Nov 2016 17:36:59 +0200 Subject: [PATCH 7/8] MAGETWO-60355: [Backport] - Production mode cannot be enabled - for 2.1 --- .../ObjectManager/Config/Compiled.php | 12 +-- .../Test/Unit/Config/CompiledTest.php | 91 ------------------- 2 files changed, 3 insertions(+), 100 deletions(-) delete mode 100644 lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php diff --git a/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php b/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php index d155432894daf..227b9444b6061 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php +++ b/lib/internal/Magento/Framework/ObjectManager/Config/Compiled.php @@ -129,15 +129,9 @@ public function getPreference($type) */ public function extend(array $configuration) { - $this->arguments = isset($configuration['arguments']) - ? array_replace($this->arguments, $configuration['arguments']) - : $this->arguments; - $this->virtualTypes = isset($configuration['instanceTypes']) - ? array_replace($this->virtualTypes, $configuration['instanceTypes']) - : $this->virtualTypes; - $this->preferences = isset($configuration['preferences']) - ? array_replace($this->preferences, $configuration['preferences']) - : $this->preferences; + $this->arguments = $configuration['arguments']; + $this->virtualTypes = $configuration['instanceTypes']; + $this->preferences = $configuration['preferences']; } /** diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php deleted file mode 100644 index 1fcf3176540db..0000000000000 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php +++ /dev/null @@ -1,91 +0,0 @@ -objectManagerHelper = new ObjectManagerHelper($this); - } - - /** - * @param array $initialData - * @param array $configuration - * @param array $expectedArguments - * @param array $expectedVirtualTypes - * @param array $expectedPreferences - * - * @dataProvider extendDataProvider - */ - public function testExtend( - array $initialData, - array $configuration, - array $expectedArguments, - array $expectedVirtualTypes, - array $expectedPreferences - ) { - /** @var CompiledConfig $compiledConfig */ - $compiledConfig = $this->objectManagerHelper->getObject(CompiledConfig::class, ['data' => $initialData]); - $compiledConfig->extend($configuration); - - foreach ($expectedArguments as $type => $arguments) { - $this->assertEquals($arguments, $compiledConfig->getArguments($type)); - } - - $this->assertEquals($expectedVirtualTypes, $compiledConfig->getVirtualTypes()); - $this->assertEquals($expectedPreferences, $compiledConfig->getPreferences()); - } - - /** - * @return array - */ - public function extendDataProvider() - { - return [ - [ - 'initialData' => [ - 'arguments' => [ - 'type1' => serialize(['argument1_1' => 'argumentValue1_1', 'argument1_2' => 'argumentValue1_2']) - ], - 'instanceTypes' => [ - 'instanceType1' => 'instanceTypeValue1', 'instanceType2' => 'instanceTypeValue2' - ], - 'preferences' => ['preference1' => 'preferenceValue1', 'preference2' => 'preferenceValue2'] - ], - 'configuration' => [ - 'arguments' => [ - 'type1' => serialize(['argument1_1' => 'newArgumentValue1_1']), - 'type2' => serialize(['argument2_1' => 'newArgumentValue2_1']) - ], - 'instanceTypes' => [ - 'instanceType2' => 'newInstanceTypeValue2', 'instanceType3' => 'newInstanceTypeValue3' - ], - 'preferences' => ['preference1' => 'newPreferenceValue1'] - ], - 'expectedArguments' => [ - 'type1' => ['argument1_1' => 'newArgumentValue1_1'], - 'type2' => ['argument2_1' => 'newArgumentValue2_1'] - ], - 'expectedVirtualTypes' => [ - 'instanceType1' => 'instanceTypeValue1', 'instanceType2' => 'newInstanceTypeValue2', - 'instanceType3' => 'newInstanceTypeValue3' - ], - 'expectedPreferences' => [ - 'preference1' => 'newPreferenceValue1', 'preference2' => 'preferenceValue2' - ] - ] - ]; - } -} From f33dd6063710520ec5baf82381dfbd73dc0622fd Mon Sep 17 00:00:00 2001 From: Oleh Posyniak Date: Wed, 2 Nov 2016 18:26:07 +0200 Subject: [PATCH 8/8] MAGETWO-59809: Scrub sensitive data during app:dump --- .../Config/Model/Config/Export/Comment.php | 3 +- .../Processor/EnvironmentPlaceholder.php | 3 +- .../Reader/Source/Deployed/SettingChecker.php | 3 +- .../Model/Placeholder/PlaceholderFactory.php | 24 +++++- .../Unit/Model/Config/Export/CommentTest.php | 1 + .../Processor/EnvironmentPlaceholderTest.php | 2 +- .../Source/Deployed/SettingCheckerTest.php | 3 +- .../Placeholder/PlaceholderFactoryTest.php | 76 +++++++++++++++++++ app/code/Magento/Config/etc/di.xml | 6 +- 9 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php diff --git a/app/code/Magento/Config/Model/Config/Export/Comment.php b/app/code/Magento/Config/Model/Config/Export/Comment.php index e08657aa4ba7e..8b9692b031c8d 100644 --- a/app/code/Magento/Config/Model/Config/Export/Comment.php +++ b/app/code/Magento/Config/Model/Config/Export/Comment.php @@ -8,7 +8,6 @@ use Magento\Config\App\Config\Source\DumpConfigSourceInterface; use Magento\Config\Model\Placeholder\PlaceholderFactory; use Magento\Config\Model\Placeholder\PlaceholderInterface; -use Magento\Config\Model\Placeholder\Environment; use Magento\Framework\App\Config\CommentInterface; /** @@ -35,7 +34,7 @@ public function __construct( PlaceholderFactory $placeholderFactory, DumpConfigSourceInterface $source ) { - $this->placeholder = $placeholderFactory->create(Environment::class); + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); $this->source = $source; } diff --git a/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php index 798d557c43767..624896257b88e 100644 --- a/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php +++ b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php @@ -5,7 +5,6 @@ */ namespace Magento\Config\Model\Config\Processor; -use Magento\Config\Model\Placeholder\Environment; use Magento\Config\Model\Placeholder\PlaceholderFactory; use Magento\Config\Model\Placeholder\PlaceholderInterface; use Magento\Framework\App\Config\Spi\PreProcessorInterface; @@ -38,7 +37,7 @@ public function __construct( ) { $this->placeholderFactory = $placeholderFactory; $this->arrayManager = $arrayManager; - $this->placeholder = $placeholderFactory->create(Environment::class); + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); } /** diff --git a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php index 13daa9725d60d..8485d09f38f45 100644 --- a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php +++ b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php @@ -10,7 +10,6 @@ use Magento\Framework\App\DeploymentConfig; use Magento\Config\Model\Placeholder\PlaceholderInterface; use Magento\Config\Model\Placeholder\PlaceholderFactory; -use Magento\Config\Model\Placeholder\Environment; use Magento\Framework\App\Config\ScopeCodeResolver; /** @@ -50,7 +49,7 @@ public function __construct( ) { $this->config = $config; $this->scopeCodeResolver = $scopeCodeResolver; - $this->placeholder = $placeholderFactory->create(Environment::class); + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); } /** diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php index 68e688614c774..3f88bc2a289c4 100644 --- a/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php @@ -5,21 +5,34 @@ */ namespace Magento\Config\Model\Placeholder; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\ObjectManagerInterface; class PlaceholderFactory { + /** + * @const string Environment type + */ + const TYPE_ENVIRONMENT = 'environment'; + /** * @var ObjectManagerInterface */ private $objectManager; + /** + * @var array + */ + private $types; + /** * @param ObjectManagerInterface $objectManager + * @param array $types */ - public function __construct(ObjectManagerInterface $objectManager) + public function __construct(ObjectManagerInterface $objectManager, array $types = []) { $this->objectManager = $objectManager; + $this->types = $types; } /** @@ -27,13 +40,18 @@ public function __construct(ObjectManagerInterface $objectManager) * * @param string $type * @return PlaceholderInterface + * @throws LocalizedException */ public function create($type) { - $object = $this->objectManager->create($type); + if (!isset($this->types[$type])) { + throw new LocalizedException(__('There is no defined type ' . $type)); + } + + $object = $this->objectManager->create($this->types[$type]); if (!$object instanceof PlaceholderInterface) { - throw new \LogicException('Object is not instance of ' . PlaceholderInterface::class); + throw new LocalizedException(__('Object is not instance of ' . PlaceholderInterface::class)); } return $object; diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php index deddafa4b3e87..c14deafd842dd 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Export/CommentTest.php @@ -42,6 +42,7 @@ protected function setUp() ->getMock(); $placeholderFactoryMock->expects($this->once()) ->method('create') + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) ->willReturn($this->placeholderMock); $this->configSourceMock = $this->getMockBuilder(DumpConfigSourceInterface::class) diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php index 71c1a6bdda425..25f9f6b3cb832 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Processor/EnvironmentPlaceholderTest.php @@ -6,7 +6,6 @@ namespace Magento\Config\Test\Unit\Model\Config\Processor; use Magento\Config\Model\Config\Processor\EnvironmentPlaceholder; -use Magento\Config\Model\Placeholder\Environment; use Magento\Config\Model\Placeholder\PlaceholderFactory; use Magento\Config\Model\Placeholder\PlaceholderInterface; use Magento\Framework\Stdlib\ArrayManager; @@ -53,6 +52,7 @@ protected function setUp() $this->placeholderFactoryMock->expects($this->any()) ->method('create') + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) ->willReturn($this->placeholderMock); $this->model = new EnvironmentPlaceholder( diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php index 4b28b8f2b27c9..75bfab85616b5 100644 --- a/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php +++ b/app/code/Magento/Config/Test/Unit/Model/Config/Reader/Source/Deployed/SettingCheckerTest.php @@ -11,7 +11,6 @@ use Magento\Framework\App\DeploymentConfig; use Magento\Config\Model\Placeholder\PlaceholderInterface; use Magento\Config\Model\Placeholder\PlaceholderFactory; -use Magento\Config\Model\Placeholder\Environment; /** * Test class for checking settings that defined in config file @@ -60,7 +59,7 @@ public function setUp() $placeholderFactoryMock->expects($this->once()) ->method('create') - ->with(Environment::class) + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) ->willReturn($this->placeholderMock); $this->checker = new SettingChecker($this->configMock, $placeholderFactoryMock, $this->scopeCodeResolverMock); diff --git a/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php b/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php new file mode 100644 index 0000000000000..e8f646e984187 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Model/Placeholder/PlaceholderFactoryTest.php @@ -0,0 +1,76 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->getMockForAbstractClass(); + $this->environmentMock = $this->getMockBuilder(Environment::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new PlaceholderFactory( + $this->objectManagerMock, + [ + PlaceholderFactory::TYPE_ENVIRONMENT => Environment::class, + 'wrongClass' => \stdClass::class, + ] + ); + } + + public function testCreate() + { + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with(Environment::class) + ->willReturn($this->environmentMock); + + $this->assertInstanceOf( + Environment::class, + $this->model->create(PlaceholderFactory::TYPE_ENVIRONMENT) + ); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage There is no defined type dummyClass + */ + public function testCreateNonExisted() + { + $this->model->create('dummyClass'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Object is not instance of Magento\Config\Model\Placeholder\PlaceholderInterface + */ + public function testCreateWrongImplementation() + { + $this->model->create('wrongClass'); + } +} diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index 687f8609bd3ee..d55303c0eacf7 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -176,9 +176,11 @@ appDumpSystemSource - + - Magento\Config\Model\Config\Structure\Element\Iterator\Tab\Proxy + + Magento\Config\Model\Placeholder\Environment +