Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Config.php
Go to the documentation of this file.
1 <?php
6 namespace Magento\Config\Model;
7 
12 
23 {
29  protected $_configData;
30 
36  protected $_eventManager;
37 
43  protected $_configStructure;
44 
50  protected $_appConfig;
51 
57  protected $_objectFactory;
58 
65 
71  protected $_configLoader;
72 
79 
83  protected $_storeManager;
84 
88  private $settingChecker;
89 
101  public function __construct(
102  \Magento\Framework\App\Config\ReinitableConfigInterface $config,
103  \Magento\Framework\Event\ManagerInterface $eventManager,
104  \Magento\Config\Model\Config\Structure $configStructure,
105  \Magento\Framework\DB\TransactionFactory $transactionFactory,
106  \Magento\Config\Model\Config\Loader $configLoader,
107  \Magento\Framework\App\Config\ValueFactory $configValueFactory,
109  SettingChecker $settingChecker = null,
110  array $data = []
111  ) {
112  parent::__construct($data);
113  $this->_eventManager = $eventManager;
114  $this->_configStructure = $configStructure;
115  $this->_transactionFactory = $transactionFactory;
116  $this->_appConfig = $config;
117  $this->_configLoader = $configLoader;
118  $this->_configValueFactory = $configValueFactory;
119  $this->_storeManager = $storeManager;
120  $this->settingChecker = $settingChecker ?: ObjectManager::getInstance()->get(SettingChecker::class);
121  }
122 
131  public function save()
132  {
133  $this->initScope();
134 
135  $sectionId = $this->getSection();
136  $groups = $this->getGroups();
137  if (empty($groups)) {
138  return $this;
139  }
140 
141  $oldConfig = $this->_getConfig(true);
142 
144  $deleteTransaction = $this->_transactionFactory->create();
146  $saveTransaction = $this->_transactionFactory->create();
147 
148  $changedPaths = [];
149  // Extends for old config data
150  $extraOldGroups = [];
151 
152  foreach ($groups as $groupId => $groupData) {
153  $this->_processGroup(
154  $groupId,
155  $groupData,
156  $groups,
157  $sectionId,
158  $extraOldGroups,
159  $oldConfig,
160  $saveTransaction,
161  $deleteTransaction
162  );
163 
164  $groupChangedPaths = $this->getChangedPaths($sectionId, $groupId, $groupData, $oldConfig, $extraOldGroups);
165  $changedPaths = \array_merge($changedPaths, $groupChangedPaths);
166  }
167 
168  try {
169  $deleteTransaction->delete();
170  $saveTransaction->save();
171 
172  // re-init configuration
173  $this->_appConfig->reinit();
174 
175  // website and store codes can be used in event implementation, so set them as well
176  $this->_eventManager->dispatch(
177  "admin_system_config_changed_section_{$this->getSection()}",
178  [
179  'website' => $this->getWebsite(),
180  'store' => $this->getStore(),
181  'changed_paths' => $changedPaths,
182  ]
183  );
184  } catch (\Exception $e) {
185  // re-init configuration
186  $this->_appConfig->reinit();
187  throw $e;
188  }
189 
190  return $this;
191  }
192 
200  private function getOriginalFieldId(Group $group, string $fieldId): string
201  {
202  if ($group->shouldCloneFields()) {
203  $cloneModel = $group->getCloneModel();
204 
206  foreach ($group->getChildren() as $field) {
207  foreach ($cloneModel->getPrefixes() as $prefix) {
208  if ($prefix['field'] . $field->getId() === $fieldId) {
209  $fieldId = $field->getId();
210  break(2);
211  }
212  }
213  }
214  }
215 
216  return $fieldId;
217  }
218 
227  private function getField(string $sectionId, string $groupId, string $fieldId): Field
228  {
230  $group = $this->_configStructure->getElement($sectionId . '/' . $groupId);
231  $fieldPath = $group->getPath() . '/' . $this->getOriginalFieldId($group, $fieldId);
232  $field = $this->_configStructure->getElement($fieldPath);
233 
234  return $field;
235  }
236 
246  private function getFieldPath(Field $field, string $fieldId, array &$oldConfig, array &$extraOldGroups): string
247  {
248  $path = $field->getGroupPath() . '/' . $fieldId;
249 
253  $configPath = $field->getConfigPath();
254  if ($configPath && strrpos($configPath, '/') > 0) {
255  // Extend old data with specified section group
256  $configGroupPath = substr($configPath, 0, strrpos($configPath, '/'));
257  if (!isset($extraOldGroups[$configGroupPath])) {
258  $oldConfig = $this->extendConfig($configGroupPath, true, $oldConfig);
259  $extraOldGroups[$configGroupPath] = true;
260  }
261  $path = $configPath;
262  }
263 
264  return $path;
265  }
266 
275  private function isValueChanged(array $oldConfig, string $path, array $fieldData): bool
276  {
277  if (isset($oldConfig[$path]['value'])) {
278  $result = !isset($fieldData['value']) || $oldConfig[$path]['value'] !== $fieldData['value'];
279  } else {
280  $result = empty($fieldData['inherit']);
281  }
282 
283  return $result;
284  }
285 
296  private function getChangedPaths(
297  string $sectionId,
298  string $groupId,
299  array $groupData,
300  array &$oldConfig,
301  array &$extraOldGroups
302  ): array {
303  $changedPaths = [];
304 
305  if (isset($groupData['fields'])) {
306  foreach ($groupData['fields'] as $fieldId => $fieldData) {
307  $field = $this->getField($sectionId, $groupId, $fieldId);
308  $path = $this->getFieldPath($field, $fieldId, $oldConfig, $extraOldGroups);
309  if ($this->isValueChanged($oldConfig, $path, $fieldData)) {
310  $changedPaths[] = $path;
311  }
312  }
313  }
314 
315  if (isset($groupData['groups'])) {
316  $subSectionId = $sectionId . '/' . $groupId;
317  foreach ($groupData['groups'] as $subGroupId => $subGroupData) {
318  $subGroupChangedPaths = $this->getChangedPaths(
319  $subSectionId,
320  $subGroupId,
321  $subGroupData,
322  $oldConfig,
323  $extraOldGroups
324  );
325  $changedPaths = \array_merge($changedPaths, $subGroupChangedPaths);
326  }
327  }
328 
329  return $changedPaths;
330  }
331 
347  protected function _processGroup(
348  $groupId,
349  array $groupData,
350  array $groups,
351  $sectionPath,
352  array &$extraOldGroups,
353  array &$oldConfig,
354  \Magento\Framework\DB\Transaction $saveTransaction,
355  \Magento\Framework\DB\Transaction $deleteTransaction
356  ) {
357  $groupPath = $sectionPath . '/' . $groupId;
358 
359  if (isset($groupData['fields'])) {
361  $group = $this->_configStructure->getElement($groupPath);
362 
363  // set value for group field entry by fieldname
364  // use extra memory
365  $fieldsetData = [];
366  foreach ($groupData['fields'] as $fieldId => $fieldData) {
367  $fieldsetData[$fieldId] = $fieldData['value'] ?? null;
368  }
369 
370  foreach ($groupData['fields'] as $fieldId => $fieldData) {
371  $isReadOnly = $this->settingChecker->isReadOnly(
372  $groupPath . '/' . $fieldId,
373  $this->getScope(),
374  $this->getScopeCode()
375  );
376 
377  if ($isReadOnly) {
378  continue;
379  }
380 
381  $field = $this->getField($sectionPath, $groupId, $fieldId);
383  $backendModel = $field->hasBackendModel()
384  ? $field->getBackendModel()
385  : $this->_configValueFactory->create();
386 
387  if (!isset($fieldData['value'])) {
388  $fieldData['value'] = null;
389  }
390  $data = [
391  'field' => $fieldId,
392  'groups' => $groups,
393  'group_id' => $group->getId(),
394  'scope' => $this->getScope(),
395  'scope_id' => $this->getScopeId(),
396  'scope_code' => $this->getScopeCode(),
397  'field_config' => $field->getData(),
398  'fieldset_data' => $fieldsetData,
399  ];
400  $backendModel->addData($data);
401  $this->_checkSingleStoreMode($field, $backendModel);
402 
403  $path = $this->getFieldPath($field, $fieldId, $extraOldGroups, $oldConfig);
404  $backendModel->setPath($path)->setValue($fieldData['value']);
405 
406  $inherit = !empty($fieldData['inherit']);
407  if (isset($oldConfig[$path])) {
408  $backendModel->setConfigId($oldConfig[$path]['config_id']);
409 
413  if (!$inherit) {
414  $saveTransaction->addObject($backendModel);
415  } else {
416  $deleteTransaction->addObject($backendModel);
417  }
418  } elseif (!$inherit) {
419  $backendModel->unsConfigId();
420  $saveTransaction->addObject($backendModel);
421  }
422  }
423  }
424 
425  if (isset($groupData['groups'])) {
426  foreach ($groupData['groups'] as $subGroupId => $subGroupData) {
427  $this->_processGroup(
428  $subGroupId,
429  $subGroupData,
430  $groups,
431  $groupPath,
432  $extraOldGroups,
433  $oldConfig,
434  $saveTransaction,
435  $deleteTransaction
436  );
437  }
438  }
439  }
440 
446  public function load()
447  {
448  if ($this->_configData === null) {
449  $this->initScope();
450  $this->_configData = $this->_getConfig(false);
451  }
452  return $this->_configData;
453  }
454 
463  public function extendConfig($path, $full = true, $oldConfig = [])
464  {
465  $extended = $this->_configLoader->getConfigByPath($path, $this->getScope(), $this->getScopeId(), $full);
466  if (is_array($oldConfig) && !empty($oldConfig)) {
467  return $oldConfig + $extended;
468  }
469  return $extended;
470  }
471 
480  public function setDataByPath($path, $value)
481  {
482  $path = trim($path);
483  if ($path === '') {
484  throw new \UnexpectedValueException('Path must not be empty');
485  }
486  $pathParts = explode('/', $path);
487  $keyDepth = count($pathParts);
488  if ($keyDepth !== 3) {
489  throw new \UnexpectedValueException(
490  "Allowed depth of configuration is 3 (<section>/<group>/<field>). Your configuration depth is "
491  . $keyDepth . " for path '$path'"
492  );
493  }
494  $data = [
495  'section' => $pathParts[0],
496  'groups' => [
497  $pathParts[1] => [
498  'fields' => [
499  $pathParts[2] => ['value' => $value],
500  ],
501  ],
502  ],
503  ];
504  $this->addData($data);
505  }
506 
513  private function initScope()
514  {
515  if ($this->getSection() === null) {
516  $this->setSection('');
517  }
518  if ($this->getWebsite() === null) {
519  $this->setWebsite('');
520  }
521  if ($this->getStore() === null) {
522  $this->setStore('');
523  }
524 
525  if ($this->getStore()) {
526  $scope = 'stores';
527  $store = $this->_storeManager->getStore($this->getStore());
528  $scopeId = (int)$store->getId();
529  $scopeCode = $store->getCode();
530  } elseif ($this->getWebsite()) {
531  $scope = 'websites';
532  $website = $this->_storeManager->getWebsite($this->getWebsite());
533  $scopeId = (int)$website->getId();
534  $scopeCode = $website->getCode();
535  } else {
536  $scope = 'default';
537  $scopeId = 0;
538  $scopeCode = '';
539  }
540  $this->setScope($scope);
541  $this->setScopeId($scopeId);
542  $this->setScopeCode($scopeCode);
543  }
544 
551  protected function _getConfig($full = true)
552  {
553  return $this->_configLoader->getConfigByPath(
554  $this->getSection(),
555  $this->getScope(),
556  $this->getScopeId(),
557  $full
558  );
559  }
560 
568  protected function _checkSingleStoreMode(
569  \Magento\Config\Model\Config\Structure\Element\Field $fieldConfig,
570  $dataObject
571  ) {
572  $isSingleStoreMode = $this->_storeManager->isSingleStoreMode();
573  if (!$isSingleStoreMode) {
574  return;
575  }
576  if (!$fieldConfig->showInDefault()) {
577  $websites = $this->_storeManager->getWebsites();
578  $singleStoreWebsite = array_shift($websites);
579  $dataObject->setScope('websites');
580  $dataObject->setWebsiteCode($singleStoreWebsite->getCode());
581  $dataObject->setScopeCode($singleStoreWebsite->getCode());
582  $dataObject->setScopeId($singleStoreWebsite->getId());
583  }
584  }
585 
594  public function getConfigDataValue($path, &$inherit = null, $configData = null)
595  {
596  $this->load();
597  if ($configData === null) {
599  }
600  if (isset($configData[$path])) {
602  $inherit = false;
603  } else {
604  $data = $this->_appConfig->getValue($path, $this->getScope(), $this->getScopeCode());
605  $inherit = true;
606  }
607 
608  return $data;
609  }
610 }
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
_checkSingleStoreMode(\Magento\Config\Model\Config\Structure\Element\Field $fieldConfig, $dataObject)
Definition: Config.php:568
$config
Definition: fraud_order.php:17
getConfigDataValue($path, &$inherit=null, $configData=null)
Definition: Config.php:594
$group
Definition: sections.phtml:16
$storeManager
__construct(\Magento\Framework\App\Config\ReinitableConfigInterface $config, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Config\Model\Config\Structure $configStructure, \Magento\Framework\DB\TransactionFactory $transactionFactory, \Magento\Config\Model\Config\Loader $configLoader, \Magento\Framework\App\Config\ValueFactory $configValueFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, SettingChecker $settingChecker=null, array $data=[])
Definition: Config.php:101
setDataByPath($path, $value)
Definition: Config.php:480
$prefix
Definition: name.phtml:25
$fieldId
Definition: element.phtml:16
$value
Definition: gender.phtml:16
extendConfig($path, $full=true, $oldConfig=[])
Definition: Config.php:463