Skip to content

Commit c0a9c42

Browse files
author
naitsirch
committed
Fix array to string conversion error when saving row system config with defaults
This PR solves issue #30314. The backend model that is designed to handle complex values serializes non-scalar values before they are persisted to database. But when the old value is loaded from config defaults (defined in config.xml) for comparison, the default value is fetched as array. When the array is casted to string it results in an array to string conversion error. This issue is fixed by serializing the default value coming from the config.
1 parent fa211bd commit c0a9c42

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

app/code/Magento/Config/Model/Config/Backend/Serialized.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\Config\Model\Config\Backend;
77

8+
use Magento\Framework\App\Config\ScopeConfigInterface;
89
use Magento\Framework\App\ObjectManager;
910
use Magento\Framework\Serialize\Serializer\Json;
1011

@@ -84,4 +85,26 @@ public function beforeSave()
8485
parent::beforeSave();
8586
return $this;
8687
}
88+
89+
/**
90+
* Get old value from existing config
91+
*
92+
* @return string
93+
*/
94+
public function getOldValue()
95+
{
96+
// If the value is retrieved from defaults defined in config.xml
97+
// it may be returned as an array.
98+
$value = $this->_config->getValue(
99+
$this->getPath(),
100+
$this->getScope() ?: ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
101+
$this->getScopeCode()
102+
);
103+
104+
if (is_array($value)) {
105+
return $this->serializer->serialize($value);
106+
}
107+
108+
return (string)$value;
109+
}
87110
}

app/code/Magento/Config/Test/Unit/Model/Config/Backend/SerializedTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\Config\Test\Unit\Model\Config\Backend;
99

1010
use Magento\Config\Model\Config\Backend\Serialized;
11+
use Magento\Framework\App\Config\ScopeConfigInterface;
1112
use Magento\Framework\Event\ManagerInterface;
1213
use Magento\Framework\Model\Context;
1314
use Magento\Framework\Serialize\Serializer\Json;
@@ -27,11 +28,14 @@ class SerializedTest extends TestCase
2728
/** @var LoggerInterface|MockObject */
2829
private $loggerMock;
2930

31+
private $scopeConfigMock;
32+
3033
protected function setUp(): void
3134
{
3235
$objectManager = new ObjectManager($this);
3336
$this->serializerMock = $this->createMock(Json::class);
3437
$this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class);
38+
$this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class);
3539
$contextMock = $this->createMock(Context::class);
3640
$eventManagerMock = $this->getMockForAbstractClass(ManagerInterface::class);
3741
$contextMock->method('getEventDispatcher')
@@ -43,6 +47,7 @@ protected function setUp(): void
4347
[
4448
'serializer' => $this->serializerMock,
4549
'context' => $contextMock,
50+
'config' => $this->scopeConfigMock,
4651
]
4752
);
4853
}
@@ -135,4 +140,29 @@ public function beforeSaveDataProvider()
135140
]
136141
];
137142
}
143+
144+
/**
145+
* If a config value is not available in core_confid_data the defaults are
146+
* loaded from the config.xml file. Those defaults may be arrays.
147+
* The Serialized backend model has to override its parent
148+
* getOldValue function, to prevent an array to string conversion error
149+
* and serialize those values.
150+
*/
151+
public function testGetOldValueWithNonScalarDefaultValue(): void
152+
{
153+
$value = [
154+
['foo' => '1', 'bar' => '2'],
155+
];
156+
$serializedValue = \json_encode($value);
157+
158+
$this->scopeConfigMock->method('getValue')->willReturn($value);
159+
$this->serializerMock->method('serialize')->willReturn($serializedValue);
160+
161+
$this->serializedConfig->setData('value', $serializedValue);
162+
163+
$oldValue = $this->serializedConfig->getOldValue();
164+
165+
$this->assertIsString($oldValue, 'Default value from the config is not serialized.');
166+
$this->assertSame($serializedValue, $oldValue);
167+
}
138168
}

0 commit comments

Comments
 (0)