/** * 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; }
/** * @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 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; }
/** * 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; } }
/** * 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; }
/** * 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; }
/** * 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]; }
public function testGetMethodReturnType() { $this->assertEquals('string', $this->model->getMethodReturnType('Magento\\Framework\\Reflection\\FieldNamer', 'getFieldNameForMethodName')); $this->assertEquals('mixed', $this->model->getMethodReturnType('Magento\\Framework\\Reflection\\TypeCaster', 'castValueToType')); $this->assertEquals('array', $this->model->getMethodReturnType('Magento\\Framework\\Reflection\\MethodsMap', 'getMethodsMap')); }
/** * 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); }