5
5
* Copyright © Magento, Inc. All rights reserved.
6
6
* See COPYING.txt for license details.
7
7
*/
8
+ declare (strict_types=1 );
8
9
9
10
namespace Magento \Framework \Webapi ;
10
11
11
- use Magento \Framework \Webapi \ServiceTypeToEntityTypeMap ;
12
12
use Magento \Framework \Api \AttributeValue ;
13
13
use Magento \Framework \Api \AttributeValueFactory ;
14
14
use Magento \Framework \Api \SimpleDataObjectConverter ;
15
15
use Magento \Framework \Exception \InputException ;
16
16
use Magento \Framework \Exception \SerializationException ;
17
+ use Magento \Framework \ObjectManager \ConfigInterface ;
17
18
use Magento \Framework \ObjectManagerInterface ;
18
19
use Magento \Framework \Phrase ;
19
20
use Magento \Framework \Reflection \MethodsMap ;
@@ -66,6 +67,11 @@ class ServiceInputProcessor implements ServicePayloadConverterInterface
66
67
*/
67
68
private $ serviceTypeToEntityTypeMap ;
68
69
70
+ /**
71
+ * @var ConfigInterface
72
+ */
73
+ private $ config ;
74
+
69
75
/**
70
76
* Initialize dependencies.
71
77
*
@@ -75,14 +81,16 @@ class ServiceInputProcessor implements ServicePayloadConverterInterface
75
81
* @param CustomAttributeTypeLocatorInterface $customAttributeTypeLocator
76
82
* @param MethodsMap $methodsMap
77
83
* @param ServiceTypeToEntityTypeMap $serviceTypeToEntityTypeMap
84
+ * @param ConfigInterface $config
78
85
*/
79
86
public function __construct (
80
87
TypeProcessor $ typeProcessor ,
81
88
ObjectManagerInterface $ objectManager ,
82
89
AttributeValueFactory $ attributeValueFactory ,
83
90
CustomAttributeTypeLocatorInterface $ customAttributeTypeLocator ,
84
91
MethodsMap $ methodsMap ,
85
- ServiceTypeToEntityTypeMap $ serviceTypeToEntityTypeMap = null
92
+ ServiceTypeToEntityTypeMap $ serviceTypeToEntityTypeMap = null ,
93
+ ConfigInterface $ config = null
86
94
) {
87
95
$ this ->typeProcessor = $ typeProcessor ;
88
96
$ this ->objectManager = $ objectManager ;
@@ -91,6 +99,8 @@ public function __construct(
91
99
$ this ->methodsMap = $ methodsMap ;
92
100
$ this ->serviceTypeToEntityTypeMap = $ serviceTypeToEntityTypeMap
93
101
?: \Magento \Framework \App \ObjectManager::getInstance ()->get (ServiceTypeToEntityTypeMap::class);
102
+ $ this ->config = $ config
103
+ ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (ConfigInterface::class);
94
104
}
95
105
96
106
/**
@@ -154,6 +164,33 @@ public function process($serviceClassName, $serviceMethodName, array $inputArray
154
164
return $ inputData ;
155
165
}
156
166
167
+ /**
168
+ * @param string $className
169
+ * @param array $data
170
+ * @return array
171
+ * @throws \ReflectionException
172
+ */
173
+ private function getConstructorData (string $ className , array $ data ): array
174
+ {
175
+ $ preferenceClass = $ this ->config ->getPreference ($ className );
176
+ $ class = new ClassReflection ($ preferenceClass ?: $ className );
177
+
178
+ $ constructor = $ class ->getConstructor ();
179
+ if ($ constructor === null ) {
180
+ return [];
181
+ }
182
+
183
+ $ res = [];
184
+ $ parameters = $ constructor ->getParameters ();
185
+ foreach ($ parameters as $ parameter ) {
186
+ if (isset ($ data [$ parameter ->getName ()])) {
187
+ $ res [$ parameter ->getName ()] = $ data [$ parameter ->getName ()];
188
+ }
189
+ }
190
+
191
+ return $ res ;
192
+ }
193
+
157
194
/**
158
195
* Creates a new instance of the given class and populates it with the array of data. The data can
159
196
* be in different forms depending on the adapter being used, REST vs. SOAP. For REST, the data is
@@ -163,6 +200,7 @@ public function process($serviceClassName, $serviceMethodName, array $inputArray
163
200
* @param array $data
164
201
* @return object the newly created and populated object
165
202
* @throws \Exception
203
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
166
204
*/
167
205
protected function _createFromArray ($ className , $ data )
168
206
{
@@ -174,9 +212,17 @@ protected function _createFromArray($className, $data)
174
212
if (is_subclass_of ($ className , self ::EXTENSION_ATTRIBUTES_TYPE )) {
175
213
$ className = substr ($ className , 0 , -strlen ('Interface ' ));
176
214
}
177
- $ object = $ this ->objectManager ->create ($ className );
178
215
216
+ // Primary method: assign to constructor parameters
217
+ $ constructorArgs = $ this ->getConstructorData ($ className , $ data );
218
+ $ object = $ this ->objectManager ->create ($ className , $ constructorArgs );
219
+
220
+ // Secondary method: fallback to setter methods
179
221
foreach ($ data as $ propertyName => $ value ) {
222
+ if (isset ($ constructorArgs [$ propertyName ])) {
223
+ continue ;
224
+ }
225
+
180
226
// Converts snake_case to uppercase CamelCase to help form getter/setter method names
181
227
// This use case is for REST only. SOAP request data is already camel cased
182
228
$ camelCaseProperty = SimpleDataObjectConverter::snakeCaseToUpperCamelCase ($ propertyName );
0 commit comments