/**
  * Convert the input array from key-value format to a list of parameters suitable for the specified class / method.
  *
  * The input array should have the field name as the key, and the value will either be a primitive or another
  * key-value array.  The top level of this array needs keys that match the names of the parameters on the
  * service method.
  *
  * Mismatched types are caught by the PHP runtime, not explicitly checked for by this code.
  *
  * @param string $serviceClassName name of the service class that we are trying to call
  * @param string $serviceMethodName name of the method that we are trying to call
  * @param array $inputArray data to send to method in key-value format
  * @return array list of parameters that can be used to call the service method
  * @throws InputException if no value is provided for required parameters
  * @throws WebapiException
  */
 public function process($serviceClassName, $serviceMethodName, array $inputArray)
 {
     $inputData = [];
     $inputError = [];
     foreach ($this->methodsMap->getMethodParams($serviceClassName, $serviceMethodName) as $param) {
         $paramName = $param[MethodsMap::METHOD_META_NAME];
         $snakeCaseParamName = strtolower(preg_replace("/(?<=\\w)(?=[A-Z])/", "_\$1", $paramName));
         if (isset($inputArray[$paramName]) || isset($inputArray[$snakeCaseParamName])) {
             $paramValue = isset($inputArray[$paramName]) ? $inputArray[$paramName] : $inputArray[$snakeCaseParamName];
             try {
                 $inputData[] = $this->convertValue($paramValue, $param[MethodsMap::METHOD_META_TYPE]);
             } catch (SerializationException $e) {
                 throw new WebapiException(new Phrase($e->getMessage()));
             }
         } else {
             if ($param[MethodsMap::METHOD_META_HAS_DEFAULT_VALUE]) {
                 $inputData[] = $param[MethodsMap::METHOD_META_DEFAULT_VALUE];
             } else {
                 $inputError[] = $paramName;
             }
         }
     }
     $this->processInputError($inputError);
     return $inputData;
 }
 /**
  * Validate service method
  *
  * @param string $serviceMethod
  * @param string $topicName
  * @param string $className
  * @param string $methodName
  * @return void
  */
 public function validateServiceMethod($serviceMethod, $topicName, $className, $methodName)
 {
     try {
         $this->methodsMap->getMethodParams($className, $methodName);
     } catch (\Exception $e) {
         throw new \LogicException(sprintf('Service method specified in the definition of topic "%s" is not available. Given "%s"', $topicName, $serviceMethod));
     }
 }
 /**
  * Extract service method metadata.
  *
  * @param string $className
  * @param string $methodName
  * @return array
  */
 public function extractMethodMetadata($className, $methodName)
 {
     $result = [Config::SCHEMA_METHOD_PARAMS => [], Config::SCHEMA_METHOD_RETURN_TYPE => $this->methodsMap->getMethodReturnType($className, $methodName), Config::SCHEMA_METHOD_HANDLER => [Config::HANDLER_TYPE => $className, Config::HANDLER_METHOD => $methodName]];
     $paramsMeta = $this->methodsMap->getMethodParams($className, $methodName);
     foreach ($paramsMeta as $paramPosition => $paramMeta) {
         $result[Config::SCHEMA_METHOD_PARAMS][] = [Config::SCHEMA_METHOD_PARAM_NAME => $paramMeta[MethodsMap::METHOD_META_NAME], Config::SCHEMA_METHOD_PARAM_POSITION => $paramPosition, Config::SCHEMA_METHOD_PARAM_IS_REQUIRED => !$paramMeta[MethodsMap::METHOD_META_HAS_DEFAULT_VALUE], Config::SCHEMA_METHOD_PARAM_TYPE => $paramMeta[MethodsMap::METHOD_META_TYPE]];
     }
     return $result;
 }
Exemple #4
0
 /**
  * @param ExtensibleDataInterface $dataObject
  * @param string $getterMethodName
  * @param string $methodName
  * @param array $value
  * @param string $interfaceName
  * @return $this
  */
 protected function setComplexValue(ExtensibleDataInterface $dataObject, $getterMethodName, $methodName, array $value, $interfaceName)
 {
     if ($interfaceName == null) {
         $interfaceName = get_class($dataObject);
     }
     $returnType = $this->methodsMapProcessor->getMethodReturnType($interfaceName, $getterMethodName);
     if ($this->typeProcessor->isTypeSimple($returnType)) {
         $dataObject->{$methodName}($value);
         return $this;
     }
     if ($this->typeProcessor->isArrayType($returnType)) {
         $type = $this->typeProcessor->getArrayItemType($returnType);
         $objects = [];
         foreach ($value as $arrayElementData) {
             $object = $this->objectFactory->create($type, []);
             $this->populateWithArray($object, $arrayElementData, $type);
             $objects[] = $object;
         }
         $dataObject->{$methodName}($objects);
         return $this;
     }
     if (is_subclass_of($returnType, '\\Magento\\Framework\\Api\\ExtensibleDataInterface')) {
         $object = $this->objectFactory->create($returnType, []);
         $this->populateWithArray($object, $value, $returnType);
     } else {
         if (is_subclass_of($returnType, '\\Magento\\Framework\\Api\\ExtensionAttributesInterface')) {
             $object = $this->extensionFactory->create(get_class($dataObject), $value);
         } else {
             $object = $this->objectFactory->create($returnType, $value);
         }
     }
     $dataObject->{$methodName}($object);
     return $this;
 }
 /**
  * Use class reflection on given data interface to build output data array
  *
  * @param mixed $dataObject
  * @param string $dataObjectType
  * @return array
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  */
 public function buildOutputDataArray($dataObject, $dataObjectType)
 {
     $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
     $outputData = [];
     /** @var MethodReflection $method */
     foreach (array_keys($methods) as $methodName) {
         if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
             continue;
         }
         $value = $dataObject->{$methodName}();
         $isMethodReturnValueRequired = $this->methodsMapProcessor->isMethodReturnValueRequired($dataObjectType, $methodName);
         if ($value === null && !$isMethodReturnValueRequired) {
             continue;
         }
         $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName);
         $key = $this->fieldNamer->getFieldNameForMethodName($methodName);
         if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES && $value === []) {
             continue;
         }
         if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES) {
             $value = $this->customAttributesProcessor->buildOutputDataArray($dataObject, $dataObjectType);
         } elseif ($key === "extension_attributes") {
             $value = $this->extensionAttributesProcessor->buildOutputDataArray($value, $returnType);
         } else {
             if (is_object($value) && !$value instanceof Phrase) {
                 $value = $this->buildOutputDataArray($value, $returnType);
             } elseif (is_array($value)) {
                 $valueResult = [];
                 $arrayElementType = substr($returnType, 0, -2);
                 foreach ($value as $singleValue) {
                     if (is_object($singleValue) && !$singleValue instanceof Phrase) {
                         $singleValue = $this->buildOutputDataArray($singleValue, $arrayElementType);
                     }
                     $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType);
                 }
                 $value = $valueResult;
             } else {
                 $value = $this->typeCaster->castValueToType($value, $returnType);
             }
         }
         $outputData[$key] = $value;
     }
     return $outputData;
 }
 /**
  * @param bool $isPermissionAllowed
  * @param array $expectedValue
  * @dataProvider buildOutputDataArrayWithPermissionProvider
  */
 public function testBuildOutputDataArrayWithPermission($isPermissionAllowed, $expectedValue)
 {
     $dataObject = new \Magento\Framework\Reflection\Test\Unit\ExtensionAttributesObject();
     $dataObjectType = 'Magento\\Framework\\Reflection\\Test\\Unit\\ExtensionAttributesObject';
     $methodName = 'getAttrName';
     $attributeName = 'attr_name';
     $attributeValue = 'attrName';
     $this->methodsMapProcessorMock->expects($this->once())->method('getMethodsMap')->with($dataObjectType)->will($this->returnValue([$methodName => []]));
     $this->methodsMapProcessorMock->expects($this->once())->method('isMethodValidForDataField')->with($dataObjectType, $methodName)->will($this->returnValue(true));
     $this->fieldNamerMock->expects($this->once())->method('getFieldNameForMethodName')->with($methodName)->will($this->returnValue($attributeName));
     $permissionName = 'Magento_Permission';
     $this->configReaderMock->expects($this->once())->method('read')->will($this->returnValue([$dataObjectType => [$attributeName => [Converter::RESOURCE_PERMISSIONS => [$permissionName]]]]));
     $this->authorizationMock->expects($this->once())->method('isAllowed')->with($permissionName)->will($this->returnValue($isPermissionAllowed));
     if ($isPermissionAllowed) {
         $this->methodsMapProcessorMock->expects($this->once())->method('getMethodReturnType')->with($dataObjectType, $methodName)->will($this->returnValue('string'));
         $this->typeCasterMock->expects($this->once())->method('castValueToType')->with($attributeValue, 'string')->will($this->returnValue($attributeValue));
     }
     $value = $this->model->buildOutputDataArray($dataObject, $dataObjectType);
     $this->assertEquals($value, $expectedValue);
 }
 /**
  * @param mixed $dataObject
  * @param string $getterMethodName
  * @param string $methodName
  * @param array $value
  * @param string $interfaceName
  * @return $this
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  */
 protected function setComplexValue($dataObject, $getterMethodName, $methodName, array $value, $interfaceName)
 {
     if ($interfaceName == null) {
         $interfaceName = get_class($dataObject);
     }
     $returnType = $this->methodsMapProcessor->getMethodReturnType($interfaceName, $getterMethodName);
     if ($this->typeProcessor->isTypeSimple($returnType)) {
         $dataObject->{$methodName}($value);
         return $this;
     }
     if ($this->typeProcessor->isArrayType($returnType)) {
         $type = $this->typeProcessor->getArrayItemType($returnType);
         $objects = [];
         foreach ($value as $arrayElementData) {
             $object = $this->objectFactory->create($type, []);
             $this->populateWithArray($object, $arrayElementData, $type);
             $objects[] = $object;
         }
         $dataObject->{$methodName}($objects);
         return $this;
     }
     if (is_subclass_of($returnType, '\\Magento\\Framework\\Api\\ExtensibleDataInterface')) {
         $object = $this->objectFactory->create($returnType, []);
         $this->populateWithArray($object, $value, $returnType);
     } else {
         if (is_subclass_of($returnType, '\\Magento\\Framework\\Api\\ExtensionAttributesInterface')) {
             foreach ($value as $extensionAttributeKey => $extensionAttributeValue) {
                 $extensionAttributeGetterMethodName = 'get' . \Magento\Framework\Api\SimpleDataObjectConverter::snakeCaseToUpperCamelCase($extensionAttributeKey);
                 $methodReturnType = $this->methodsMapProcessor->getMethodReturnType($returnType, $extensionAttributeGetterMethodName);
                 $extensionAttributeType = $this->typeProcessor->isArrayType($methodReturnType) ? $this->typeProcessor->getArrayItemType($methodReturnType) : $methodReturnType;
                 if ($this->typeProcessor->isTypeSimple($extensionAttributeType)) {
                     $value[$extensionAttributeKey] = $extensionAttributeValue;
                 } else {
                     if ($this->typeProcessor->isArrayType($methodReturnType)) {
                         foreach ($extensionAttributeValue as $key => $extensionAttributeArrayValue) {
                             $extensionAttribute = $this->objectFactory->create($extensionAttributeType, []);
                             $this->populateWithArray($extensionAttribute, $extensionAttributeArrayValue, $extensionAttributeType);
                             $value[$extensionAttributeKey][$key] = $extensionAttribute;
                         }
                     } else {
                         $value[$extensionAttributeKey] = $this->objectFactory->create($extensionAttributeType, ['data' => $extensionAttributeValue]);
                     }
                 }
             }
             $object = $this->extensionFactory->create(get_class($dataObject), ['data' => $value]);
         } else {
             $object = $this->objectFactory->create($returnType, $value);
         }
     }
     $dataObject->{$methodName}($object);
     return $this;
 }
Exemple #8
0
 /**
  * Ensure that specified type is either a simple type or a valid service data type.
  *
  * @param string $typeName
  * @return $this
  * @throws \Exception In case when type is invalid
  */
 protected function validateType($typeName)
 {
     if ($this->typeProcessor->isTypeSimple($typeName)) {
         return $this;
     }
     if ($this->typeProcessor->isArrayType($typeName)) {
         $arrayItemType = $this->typeProcessor->getArrayItemType($typeName);
         $this->methodsMap->getMethodsMap($arrayItemType);
     } else {
         $this->methodsMap->getMethodsMap($typeName);
     }
     return $this;
 }
 /**
  * Writes out the extension attributes in an array.
  *
  * @param ExtensionAttributeInterface $dataObject
  * @param string $dataObjectType
  * @return array
  * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  */
 public function buildOutputDataArray(ExtensionAttributesInterface $dataObject, $dataObjectType)
 {
     $methods = $this->methodsMapProcessor->getMethodsMap($dataObjectType);
     $outputData = [];
     /** @var MethodReflection $method */
     foreach (array_keys($methods) as $methodName) {
         if (!$this->methodsMapProcessor->isMethodValidForDataField($dataObjectType, $methodName)) {
             continue;
         }
         $key = $this->fieldNamer->getFieldNameForMethodName($methodName);
         if ($this->isPermissionChecked && !$this->isAttributePermissionValid($dataObjectType, $key)) {
             continue;
         }
         $value = $dataObject->{$methodName}();
         if ($value === null) {
             // all extension attributes are optional so don't need to check if isRequired
             continue;
         }
         $returnType = $this->methodsMapProcessor->getMethodReturnType($dataObjectType, $methodName);
         if (is_object($value) && !$value instanceof Phrase) {
             $value = $this->dataObjectProcessor->buildOutputDataArray($value, $returnType);
         } elseif (is_array($value)) {
             $valueResult = [];
             $arrayElementType = substr($returnType, 0, -2);
             foreach ($value as $singleValue) {
                 if (is_object($singleValue) && !$singleValue instanceof Phrase) {
                     $singleValue = $this->dataObjectProcessor->buildOutputDataArray($singleValue, $arrayElementType);
                 }
                 $valueResult[] = $this->typeCaster->castValueToType($singleValue, $arrayElementType);
             }
             $value = $valueResult;
         } else {
             $value = $this->typeCaster->castValueToType($value, $returnType);
         }
         $outputData[$key] = $value;
     }
     return $outputData;
 }
 /**
  * Converts the incoming data into scalar or an array of scalars format.
  *
  * If the data provided is null, then an empty array is returned.  Otherwise, if the data is an object, it is
  * assumed to be a Data Object and converted to an associative array with keys representing the properties of the
  * Data Object.
  * Nested Data Objects are also converted.  If the data provided is itself an array, then we iterate through the
  * contents and convert each piece individually.
  *
  * @param mixed $data
  * @param string $serviceClassName
  * @param string $serviceMethodName
  * @return array|int|string|bool|float Scalar or array of scalars
  */
 public function process($data, $serviceClassName, $serviceMethodName)
 {
     /** @var string $dataType */
     $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
     if (is_array($data)) {
         $result = [];
         $arrayElementType = substr($dataType, 0, -2);
         foreach ($data as $datum) {
             if (is_object($datum)) {
                 $datum = $this->processDataObject($this->dataObjectProcessor->buildOutputDataArray($datum, $arrayElementType));
             }
             $result[] = $datum;
         }
         return $result;
     } elseif (is_object($data)) {
         return $this->processDataObject($this->dataObjectProcessor->buildOutputDataArray($data, $dataType));
     } elseif ($data === null) {
         return [];
     } else {
         /** No processing is required for scalar types */
         return $data;
     }
 }
Exemple #11
0
 /**
  * Get message schema defined by service method signature.
  *
  * @param \DOMNode $topicNode
  * @return array
  */
 protected function extractSchemaDefinedByServiceMethod($topicNode)
 {
     $topicAttributes = $topicNode->attributes;
     if (!$topicAttributes->getNamedItem('schema')) {
         return null;
     }
     $topicName = $topicAttributes->getNamedItem('name')->nodeValue;
     list($className, $methodName) = $this->parseServiceMethod($topicAttributes->getNamedItem('schema')->nodeValue, $topicName);
     $result = [Config::SCHEMA_METHOD_PARAMS => [], Config::SCHEMA_METHOD_RETURN_TYPE => $this->methodsMap->getMethodReturnType($className, $methodName), Config::SCHEMA_METHOD_HANDLER => [Config::HANDLER_TYPE => $className, Config::HANDLER_METHOD => $methodName]];
     $paramsMeta = $this->methodsMap->getMethodParams($className, $methodName);
     foreach ($paramsMeta as $paramPosition => $paramMeta) {
         $result[Config::SCHEMA_METHOD_PARAMS][] = [Config::SCHEMA_METHOD_PARAM_NAME => $paramMeta[MethodsMap::METHOD_META_NAME], Config::SCHEMA_METHOD_PARAM_POSITION => $paramPosition, Config::SCHEMA_METHOD_PARAM_IS_REQUIRED => !$paramMeta[MethodsMap::METHOD_META_HAS_DEFAULT_VALUE], Config::SCHEMA_METHOD_PARAM_TYPE => $paramMeta[MethodsMap::METHOD_META_TYPE]];
     }
     return $result;
 }
 /**
  * @param array $data1
  * @param array $data2
  * @dataProvider dataProviderForTestMergeDataObjects
  */
 public function testMergeDataObjects($data1, $data2)
 {
     /** @var \Magento\Customer\Model\Data\Address $addressDataObject */
     $firstAddressDataObject = $this->objectManager->getObject('Magento\\Customer\\Model\\Data\\Address', ['dataObjectHelper' => $this->dataObjectHelper]);
     /** @var \Magento\Customer\Model\Data\Region $regionDataObject */
     $firstRegionDataObject = $this->objectManager->getObject('Magento\\Customer\\Model\\Data\\Region', ['dataObjectHelper' => $this->dataObjectHelper]);
     $firstRegionDataObject->setRegionId($data1['region']['region_id']);
     $firstRegionDataObject->setRegion($data1['region']['region']);
     if (isset($data1['id'])) {
         $firstAddressDataObject->setId($data1['id']);
     }
     if (isset($data1['country_id'])) {
         $firstAddressDataObject->setCountryId($data1['country_id']);
     }
     $firstAddressDataObject->setStreet($data1['street']);
     $firstAddressDataObject->setIsDefaultShipping($data1['default_shipping']);
     $firstAddressDataObject->setRegion($firstRegionDataObject);
     $secondAddressDataObject = $this->objectManager->getObject('Magento\\Customer\\Model\\Data\\Address', ['dataObjectHelper' => $this->dataObjectHelper]);
     /** @var \Magento\Customer\Model\Data\Region $regionDataObject */
     $secondRegionDataObject = $this->objectManager->getObject('Magento\\Customer\\Model\\Data\\Region', ['dataObjectHelper' => $this->dataObjectHelper]);
     $secondRegionDataObject->setRegionId($data2['region']['region_id']);
     $secondRegionDataObject->setRegion($data2['region']['region']);
     if (isset($data2['id'])) {
         $secondAddressDataObject->setId($data2['id']);
     }
     if (isset($data2['country_id'])) {
         $secondAddressDataObject->setCountryId($data2['country_id']);
     }
     $secondAddressDataObject->setStreet($data2['street']);
     $secondAddressDataObject->setIsDefaultShipping($data2['default_shipping']);
     $secondAddressDataObject->setRegion($secondRegionDataObject);
     $this->objectProcessorMock->expects($this->once())->method('buildOutputDataArray')->with($secondAddressDataObject, get_class($firstAddressDataObject))->willReturn($data2);
     $this->methodsMapProcessor->expects($this->at(0))->method('getMethodReturnType')->with('Magento\\Customer\\Model\\Data\\Address', 'getStreet')->willReturn('string[]');
     $this->methodsMapProcessor->expects($this->at(1))->method('getMethodReturnType')->with('Magento\\Customer\\Model\\Data\\Address', 'getRegion')->willReturn('\\Magento\\Customer\\Api\\Data\\RegionInterface');
     $this->objectFactoryMock->expects($this->once())->method('create')->with('\\Magento\\Customer\\Api\\Data\\RegionInterface', [])->willReturn($secondRegionDataObject);
     $this->dataObjectHelper->mergeDataObjects(get_class($firstAddressDataObject), $firstAddressDataObject, $secondAddressDataObject);
     $this->assertSame($firstAddressDataObject->getId(), $secondAddressDataObject->getId());
     $this->assertSame($firstAddressDataObject->getCountryId(), $secondAddressDataObject->getCountryId());
     $this->assertSame($firstAddressDataObject->getStreet(), $secondAddressDataObject->getStreet());
     $this->assertSame($firstAddressDataObject->isDefaultShipping(), $secondAddressDataObject->isDefaultShipping());
     $this->assertSame($firstAddressDataObject->getRegion(), $secondAddressDataObject->getRegion());
 }
Exemple #13
0
 /**
  * Convert service response into format acceptable by SoapServer.
  *
  * @param object|array|string|int|float|null $data
  * @param string $serviceClassName
  * @param string $serviceMethodName
  * @return array
  * @throws \InvalidArgumentException
  */
 protected function _prepareResponseData($data, $serviceClassName, $serviceMethodName)
 {
     /** @var string $dataType */
     $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
     $result = null;
     if (is_object($data)) {
         $result = $this->_dataObjectConverter->convertKeysToCamelCase($this->_dataObjectProcessor->buildOutputDataArray($data, $dataType));
     } elseif (is_array($data)) {
         $dataType = substr($dataType, 0, -2);
         foreach ($data as $key => $value) {
             if ($value instanceof ExtensibleDataInterface || $value instanceof MetadataObjectInterface) {
                 $result[] = $this->_dataObjectConverter->convertKeysToCamelCase($this->_dataObjectProcessor->buildOutputDataArray($value, $dataType));
             } else {
                 $result[$key] = $value;
             }
         }
     } elseif (is_scalar($data) || $data === null) {
         $result = $data;
     } else {
         throw new \InvalidArgumentException("Service returned result in invalid format.");
     }
     return [self::RESULT_NODE_NAME => $result];
 }
Exemple #14
0
 /**
  * @param string $type
  * @param string $methodName
  * @param bool $expectedResult
  * @dataProvider isMethodReturnValueRequiredProvider
  */
 public function testIsMethodReturnValueRequired($type, $methodName, $expectedResult)
 {
     $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult);
 }
 /**
  * Converts the incoming data into scalar or an array of scalars format.
  *
  * If the data provided is null, then an empty array is returned.  Otherwise, if the data is an object, it is
  * assumed to be a Data Object and converted to an associative array with keys representing the properties of the
  * Data Object.
  * Nested Data Objects are also converted.  If the data provided is itself an array, then we iterate through the
  * contents and convert each piece individually.
  *
  * @param mixed $data
  * @param string $serviceClassName
  * @param string $serviceMethodName
  * @return array|int|string|bool|float Scalar or array of scalars
  */
 public function process($data, $serviceClassName, $serviceMethodName)
 {
     /** @var string $dataType */
     $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
     return $this->convertValue($data, $dataType);
 }