Skip to content

Commit

Permalink
Merge pull request #889 from magento-falcons/MAGETWO-65085
Browse files Browse the repository at this point in the history
Task
- MAGETWO-65085 [PR] Delivery of deployment improvements
Story
- MAGETWO-63084 Sync config file with DB: Validation
- MAGETWO-62736 Rename config.local.php file, use env.php file as configs storage
- MAGETWO-63381 CLI Improvements: Configuration management - Hide sensitive values from config:show command
- MAGETWO-64223 CLI Improvements: Configuration management - Add validations to config:set command
- MAGETWO-63095 User can change the Interface Locale only to locales that are already deployed.
  • Loading branch information
VladimirZaets authored Mar 6, 2017
2 parents a6b6599 + 54cbf40 commit 3f75fac
Show file tree
Hide file tree
Showing 79 changed files with 3,991 additions and 601 deletions.
18 changes: 16 additions & 2 deletions app/code/Magento/Backend/Block/System/Account/Edit/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/
namespace Magento\Backend\Block\System\Account\Edit;

use Magento\Framework\App\ObjectManager;
use Magento\Framework\Locale\OptionInterface;

/**
* Adminhtml edit admin user account form
*
Expand All @@ -29,6 +32,13 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
*/
protected $_localeLists;

/**
* Operates with deployed locales.
*
* @var OptionInterface
*/
private $deployedLocales;

/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
Expand All @@ -37,6 +47,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
* @param \Magento\Backend\Model\Auth\Session $authSession
* @param \Magento\Framework\Locale\ListsInterface $localeLists
* @param array $data
* @param OptionInterface $deployedLocales Operates with deployed locales
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
Expand All @@ -45,11 +56,14 @@ public function __construct(
\Magento\User\Model\UserFactory $userFactory,
\Magento\Backend\Model\Auth\Session $authSession,
\Magento\Framework\Locale\ListsInterface $localeLists,
array $data = []
array $data = [],
OptionInterface $deployedLocales = null
) {
$this->_userFactory = $userFactory;
$this->_authSession = $authSession;
$this->_localeLists = $localeLists;
$this->deployedLocales = $deployedLocales
?: ObjectManager::getInstance()->get(OptionInterface::class);
parent::__construct($context, $registry, $formFactory, $data);
}

Expand Down Expand Up @@ -121,7 +135,7 @@ protected function _prepareForm()
'name' => 'interface_locale',
'label' => __('Interface Locale'),
'title' => __('Interface Locale'),
'values' => $this->_localeLists->getTranslatedOptionLocales(),
'values' => $this->deployedLocales->getTranslatedOptionLocales(),
'class' => 'select'
]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public function process($path, $value, $scope, $scopeCode)
$backendModel->beforeSave();

$this->deploymentConfigWriter->saveConfig(
[ConfigFilePool::APP_CONFIG => $this->arrayManager->set($configPath, [], $backendModel->getValue())],
[ConfigFilePool::APP_ENV => $this->arrayManager->set($configPath, [], $backendModel->getValue())],
false
);

Expand Down
33 changes: 29 additions & 4 deletions app/code/Magento/Config/Console/Command/ConfigSetCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace Magento\Config\Console\Command;

use Magento\Config\Console\Command\ConfigSet\ConfigSetProcessorFactory;
use Magento\Config\Model\Config\PathValidatorFactory;
use Magento\Framework\App\Area;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Scope\ValidatorInterface;
Expand Down Expand Up @@ -33,33 +34,49 @@ class ConfigSetCommand extends Command
/**#@-*/

/**
* The factory for config:set processors.
*
* @var ConfigSetProcessorFactory
*/
private $configSetProcessorFactory;

/**
* Scope validator.
*
* @var ValidatorInterface
*/
private $validator;

/**
* Scope manager.
*
* @var ScopeInterface
*/
private $scope;

/**
* @param ConfigSetProcessorFactory $configSetProcessorFactory
* @param ValidatorInterface $validator
* @param ScopeInterface $scope
* The factory for path validator.
*
* @var PathValidatorFactory
*/
private $pathValidatorFactory;

/**
* @param ConfigSetProcessorFactory $configSetProcessorFactory The factory for config:set processors
* @param ValidatorInterface $validator Scope validator
* @param ScopeInterface $scope Scope manager
* @param PathValidatorFactory $pathValidatorFactory The factory for path validator
*/
public function __construct(
ConfigSetProcessorFactory $configSetProcessorFactory,
ValidatorInterface $validator,
ScopeInterface $scope
ScopeInterface $scope,
PathValidatorFactory $pathValidatorFactory
) {
$this->configSetProcessorFactory = $configSetProcessorFactory;
$this->validator = $validator;
$this->scope = $scope;
$this->pathValidatorFactory = $pathValidatorFactory;

parent::__construct();
}
Expand Down Expand Up @@ -118,6 +135,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
// Emulating adminhtml scope to be able to read configs.
$this->scope->setCurrentScope(Area::AREA_ADMINHTML);

/**
* Validates the entered config path.
* Requires emulated area.
*/
$this->pathValidatorFactory->create()->validate(
$input->getArgument(ConfigSetCommand::ARG_PATH)
);

$processor = $input->getOption(static::OPTION_LOCK)
? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK)
: $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@
use Magento\Config\Model\Config\Structure\Element\Field;
use Magento\Framework\Config\ScopeInterface;
use Magento\Framework\App\Area;
use Magento\Config\Model\Config\Backend\Encrypted;

/**
* Class processes values using backend model which declared in system.xml.
*/
class ValueProcessor
{
/**
* Placeholder for the output of sensitive data.
*/
const SAFE_PLACEHOLDER = '******';

/**
* System configuration structure factory.
*
Expand Down Expand Up @@ -55,7 +61,7 @@ public function __construct(
}

/**
* Processes value using backend model.
* Processes value to display using backend model.
*
* @param string $scope The scope of configuration. E.g. 'default', 'website' or 'store'
* @param string $scopeCode The scope code of configuration
Expand All @@ -78,6 +84,11 @@ public function process($scope, $scopeCode, $value, $path)
$backendModel = $field && $field->hasBackendModel()
? $field->getBackendModel()
: $this->configValueFactory->create();

if ($backendModel instanceof Encrypted) {
return $value ? self::SAFE_PLACEHOLDER : null;
}

$backendModel->setPath($path);
$backendModel->setScope($scope);
$backendModel->setScopeId($scopeCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
try {
$this->scope = $input->getOption(self::INPUT_OPTION_SCOPE);
$this->scopeCode = $input->getOption(self::INPUT_OPTION_SCOPE_CODE);
$this->inputPath = $input->getArgument(self::INPUT_ARGUMENT_PATH);
$this->inputPath = trim($input->getArgument(self::INPUT_ARGUMENT_PATH), '/');

$this->scopeValidator->isValid($this->scope, $this->scopeCode);
$configPath = $this->pathResolver->resolve($this->inputPath, $this->scope, $this->scopeCode);
Expand Down
47 changes: 47 additions & 0 deletions app/code/Magento/Config/Model/Config/PathValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Config\Model\Config;

use Magento\Framework\Exception\ValidatorException;

/**
* Validates the config path by config structure schema.
*/
class PathValidator
{
/**
* The config structure.
*
* @var Structure
*/
private $structure;

/**
* @param Structure $structure The config structure
*/
public function __construct(Structure $structure)
{
$this->structure = $structure;
}

/**
* Checks whether the config path present in configuration structure.
*
* @param string $path The config path
* @return true The result of validation
* @throws ValidatorException If provided path is not valid
*/
public function validate($path)
{
$allPaths = $this->structure->getFieldPaths();

if (!array_key_exists($path, $allPaths)) {
throw new ValidatorException(__('The "%1" path does not exist', $path));
}

return true;
}
}
81 changes: 78 additions & 3 deletions app/code/Magento/Config/Model/Config/Structure.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Config\Model\Config;

/**
* System configuration structure
* System configuration structure.
*/
namespace Magento\Config\Model\Config;

class Structure implements \Magento\Config\Model\Config\Structure\SearchInterface
{
/**
Expand Down Expand Up @@ -251,4 +250,80 @@ protected function _getGroupFieldPathsByAttribute(array $fields, $parentPath, $a
}
return $result;
}

/**
* Collects config paths and their structure paths from configuration files.
* Returns the map of config paths and their structure paths.
*
* All paths are declared in module's system.xml.
*
* ```xml
* <section id="section_id">
* <group id="group_id" ...>
* <field id="field_one_id" ...>
* <label>Field One</label>
* ...
* </field>
* <field id="field_two_id" ...>
* <label>Field Two</label>
* <config_path>section/group/field</config_path>
* ...
* </field>
* </group>
* </section>
* ```
* If <config_path> node does not exist, then config path duplicates structure path.
* The result of this example will be:
*
* ```php
* [
* 'section_id/group_id/field_one_id' => [
* 'section_id/group_id/field_one_id'
* ],
* 'section/group/field' => [
* 'section_id/group_id/field_two_id'
* ]
*```
*
* @return array An array of config path to config structure path map
*/
public function getFieldPaths()
{
$sections = !empty($this->_data['sections']) ? $this->_data['sections'] : [];

return $this->getFieldsRecursively($sections);
}

/**
* Iteration that collects config field paths recursively from config files.
*
* @param array $elements The elements to be parsed
* @return array An array of config path to config structure path map
*/
private function getFieldsRecursively(array $elements = [])
{
$result = [];

foreach ($elements as $element) {
if (isset($element['children'])) {
$result = array_replace_recursive(
$result,
$this->getFieldsRecursively($element['children'])
);
} else {
if ($element['_elementType'] === 'field' && isset($element['label'])) {
$structurePath = (isset($element['path']) ? $element['path'] . '/' : '') . $element['id'];
$configPath = isset($element['config_path']) ? $element['config_path'] : $structurePath;

if (!isset($result[$configPath])) {
$result[$configPath] = [];
}

$result[$configPath][] = $structurePath;
}
}
}

return $result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public function testProcess($path, $value, $scope, $scopeCode)
->method('saveConfig')
->with(
[
ConfigFilePool::APP_CONFIG => [
ConfigFilePool::APP_ENV => [
'system' => [
'default' => [
'test' => [
Expand Down Expand Up @@ -234,7 +234,7 @@ public function testProcessBackendModelNotExists()
->method('saveConfig')
->with(
[
ConfigFilePool::APP_CONFIG => [
ConfigFilePool::APP_ENV => [
'system' => [
'default' => [
'test' => [
Expand Down
Loading

0 comments on commit 3f75fac

Please sign in to comment.