55 * Copyright © Magento, Inc. All rights reserved.
66 * See COPYING.txt for license details.
77 */
8+ declare (strict_types=1 );
89
910namespace Magento \Framework \Webapi ;
1011
11- use Magento \Framework \Webapi \ServiceTypeToEntityTypeMap ;
1212use Magento \Framework \Api \AttributeValue ;
1313use Magento \Framework \Api \AttributeValueFactory ;
1414use Magento \Framework \Api \SimpleDataObjectConverter ;
1515use Magento \Framework \Exception \InputException ;
1616use Magento \Framework \Exception \SerializationException ;
17+ use Magento \Framework \ObjectManager \ConfigInterface ;
1718use Magento \Framework \ObjectManagerInterface ;
1819use Magento \Framework \Phrase ;
1920use Magento \Framework \Reflection \MethodsMap ;
@@ -66,6 +67,11 @@ class ServiceInputProcessor implements ServicePayloadConverterInterface
6667 */
6768 private $ serviceTypeToEntityTypeMap ;
6869
70+ /**
71+ * @var ConfigInterface
72+ */
73+ private $ config ;
74+
6975 /**
7076 * Initialize dependencies.
7177 *
@@ -75,14 +81,16 @@ class ServiceInputProcessor implements ServicePayloadConverterInterface
7581 * @param CustomAttributeTypeLocatorInterface $customAttributeTypeLocator
7682 * @param MethodsMap $methodsMap
7783 * @param ServiceTypeToEntityTypeMap $serviceTypeToEntityTypeMap
84+ * @param ConfigInterface $config
7885 */
7986 public function __construct (
8087 TypeProcessor $ typeProcessor ,
8188 ObjectManagerInterface $ objectManager ,
8289 AttributeValueFactory $ attributeValueFactory ,
8390 CustomAttributeTypeLocatorInterface $ customAttributeTypeLocator ,
8491 MethodsMap $ methodsMap ,
85- ServiceTypeToEntityTypeMap $ serviceTypeToEntityTypeMap = null
92+ ServiceTypeToEntityTypeMap $ serviceTypeToEntityTypeMap = null ,
93+ ConfigInterface $ config = null
8694 ) {
8795 $ this ->typeProcessor = $ typeProcessor ;
8896 $ this ->objectManager = $ objectManager ;
@@ -91,6 +99,8 @@ public function __construct(
9199 $ this ->methodsMap = $ methodsMap ;
92100 $ this ->serviceTypeToEntityTypeMap = $ serviceTypeToEntityTypeMap
93101 ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (ServiceTypeToEntityTypeMap::class);
102+ $ this ->config = $ config
103+ ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (ConfigInterface::class);
94104 }
95105
96106 /**
@@ -154,6 +164,33 @@ public function process($serviceClassName, $serviceMethodName, array $inputArray
154164 return $ inputData ;
155165 }
156166
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+
157194 /**
158195 * Creates a new instance of the given class and populates it with the array of data. The data can
159196 * 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
163200 * @param array $data
164201 * @return object the newly created and populated object
165202 * @throws \Exception
203+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
166204 */
167205 protected function _createFromArray ($ className , $ data )
168206 {
@@ -174,9 +212,17 @@ protected function _createFromArray($className, $data)
174212 if (is_subclass_of ($ className , self ::EXTENSION_ATTRIBUTES_TYPE )) {
175213 $ className = substr ($ className , 0 , -strlen ('Interface ' ));
176214 }
177- $ object = $ this ->objectManager ->create ($ className );
178215
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
179221 foreach ($ data as $ propertyName => $ value ) {
222+ if (isset ($ constructorArgs [$ propertyName ])) {
223+ continue ;
224+ }
225+
180226 // Converts snake_case to uppercase CamelCase to help form getter/setter method names
181227 // This use case is for REST only. SOAP request data is already camel cased
182228 $ camelCaseProperty = SimpleDataObjectConverter::snakeCaseToUpperCamelCase ($ propertyName );
0 commit comments