/** * Add separate flow for annotated data objects, all other objects are processed by original code. * * @param \Magento\Framework\Webapi\ServiceInputProcessor $subject * @param \Closure $proceed * @param $data * @param $type * @return mixed */ public function aroundConvertValue(\Magento\Framework\Webapi\ServiceInputProcessor $subject, \Closure $proceed, $data, $type) { $result = null; if (is_subclass_of($type, \Flancer32\Lib\DataObject::class)) { if ($this->_typeProcessor->isTypeSimple($type) || $this->_typeProcessor->isTypeAny($type)) { $result = $this->_typeProcessor->processSimpleAndAnyType($data, $type); } else { /** Complex type or array of complex types */ $isArrayType = $this->_typeProcessor->isArrayType($type); if ($isArrayType) { // Initializing the result for array type else it will return null for empty array $itemType = $this->_typeProcessor->getArrayItemType($type); if (is_array($data)) { $result = []; foreach ($data as $key => $item) { $result[$key] = $this->_parser->parseArrayData($itemType, $item); } } } else { if (is_null($data)) { // do nothing, result is null } else { $result = $this->_parser->parseArrayData($type, $data); } } } } else { $result = $proceed($data, $type); } return $result; }
public function testIsTypeSimple() { $this->assertTrue($this->_typeProcessor->isTypeSimple('string')); $this->assertTrue($this->_typeProcessor->isTypeSimple('string[]')); $this->assertTrue($this->_typeProcessor->isTypeSimple('int')); $this->assertTrue($this->_typeProcessor->isTypeSimple('float')); $this->assertTrue($this->_typeProcessor->isTypeSimple('double')); $this->assertTrue($this->_typeProcessor->isTypeSimple('boolean')); $this->assertFalse($this->_typeProcessor->isTypeSimple('blah')); }
/** * 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; }
/** * @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; }
/** * Convert data from array to Data Object representation if type is Data Object or array of Data Objects. * * @param mixed $data * @param string $type Convert given value to the this type * @return mixed * @throws \Magento\Framework\Exception\LocalizedException */ public function convertValue($data, $type) { $isArrayType = $this->typeProcessor->isArrayType($type); if ($isArrayType && isset($data['item'])) { $data = $this->_removeSoapItemNode($data); } if ($this->typeProcessor->isTypeSimple($type) || $this->typeProcessor->isTypeAny($type)) { $result = $this->typeProcessor->processSimpleAndAnyType($data, $type); } else { /** Complex type or array of complex types */ if ($isArrayType) { // Initializing the result for array type else it will return null for empty array $result = is_array($data) ? [] : null; $itemType = $this->typeProcessor->getArrayItemType($type); if (is_array($data)) { foreach ($data as $key => $item) { $result[$key] = $this->_createFromArray($itemType, $item); } } } else { $result = $this->_createFromArray($type, $data); } } return $result; }
/** * Convert data from array to Data Object representation if type is Data Object or array of Data Objects. * * @param mixed $value * @param string $type Convert given value to the this type * @return mixed * @throws WebapiException * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function _convertValue($value, $type) { $isArrayType = $this->typeProcessor->isArrayType($type); if ($isArrayType && isset($value['item'])) { $value = $this->_removeSoapItemNode($value); } if ($this->typeProcessor->isTypeSimple($type) || $this->typeProcessor->isTypeAny($type)) { try { $result = $this->typeProcessor->processSimpleAndAnyType($value, $type); } catch (SerializationException $e) { throw new WebapiException(new Phrase($e->getMessage())); } } else { /** Complex type or array of complex types */ if ($isArrayType) { // Initializing the result for array type else it will return null for empty array $result = is_array($value) ? [] : null; $itemType = $this->typeProcessor->getArrayItemType($type); if (is_array($value)) { foreach ($value as $key => $item) { $result[$key] = $this->_createFromArray($itemType, $item); } } } else { $result = $this->_createFromArray($type, $value); } } return $result; }
/** * Analyze $type and save type properties into the registry. * * @param string $type * @return \Praxigento\Core\Reflection\Data\Property[] array with type properties or empty array for simple types. */ public function register($type) { $typeNorm = $this->_toolsType->normalizeType($type); $isSimple = $this->_typeProcessor->isTypeSimple($typeNorm); if (!isset($this->_registry[$typeNorm])) { if (!$isSimple) { /* analyze properties for complex type */ $this->_registry[$typeNorm] = []; /* process annotated methods */ /** @var \Zend\Code\Reflection\ClassReflection $reflection */ $reflection = new \Zend\Code\Reflection\ClassReflection($typeNorm); $docBlock = $reflection->getDocBlock(); if ($docBlock) { $this->_processDocBlock($typeNorm, $docBlock); } /* process normal methods (not annotated) */ $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC); $this->_processMethods($typeNorm, $methods); } else { /* this is simple type w/o props */ $this->_registry[$typeNorm] = []; } } return $this->_registry[$typeNorm]; }
/** * Process array of types. * * @param string $type * @param array $callInfo * @return void */ protected function _processArrayParameter($type, $callInfo = []) { $arrayItemType = $this->_typeProcessor->getArrayItemType($type); $arrayTypeName = $this->_typeProcessor->translateArrayTypeName($type); if (!$this->_typeProcessor->isTypeSimple($arrayItemType) && !$this->_typeProcessor->isTypeAny($arrayItemType)) { $this->addComplexType($arrayItemType, $callInfo); } $arrayTypeParameters = [self::ARRAY_ITEM_KEY_NAME => ['type' => $arrayItemType, 'required' => false, 'isArray' => true, 'documentation' => sprintf('An item of %s.', $arrayTypeName)]]; $arrayTypeData = ['documentation' => sprintf('An array of %s items.', $arrayItemType), 'parameters' => $arrayTypeParameters]; $this->_typeProcessor->setTypeData($arrayTypeName, $arrayTypeData); $this->addComplexType($arrayTypeName, $callInfo); }
/** * @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; }
/** * Process call info data from interface. * * @param array $interface * @param string $serviceName * @param string $methodName * @return void */ protected function _processInterfaceCallInfo($interface, $serviceName, $methodName) { foreach ($interface as $direction => $interfaceData) { $direction = $direction == 'in' ? 'requiredInput' : 'returned'; foreach ($interfaceData['parameters'] as $parameterData) { $parameterType = $parameterData['type']; if (!$this->_typeProcessor->isTypeSimple($parameterType) && !$this->_typeProcessor->isTypeAny($parameterType)) { $operation = $this->getOperationName($serviceName, $methodName); if ($parameterData['required']) { $condition = $direction == 'requiredInput' ? 'yes' : 'always'; } else { $condition = $direction == 'requiredInput' ? 'no' : 'conditionally'; } $callInfo = []; $callInfo[$direction][$condition]['calls'][] = $operation; $this->_typeProcessor->setTypeData($parameterType, ['callInfo' => $callInfo]); } } } }
/** * @param string $methodName * @param string $key * @param array $value * @return $this */ protected function setComplexValue($methodName, $key, array $value) { $returnType = $this->objectProcessor->getMethodReturnType($this->_getDataObjectType(), $methodName); if ($this->typeProcessor->isTypeSimple($returnType)) { $this->data[$key] = $value; return $this; } if ($this->typeProcessor->isArrayType($returnType)) { $type = $this->typeProcessor->getArrayItemType($returnType); $dataBuilder = $this->dataBuilderFactory->getDataBuilder($type); $objects = []; foreach ($value as $arrayElementData) { $objects[] = $dataBuilder->populateWithArray($arrayElementData)->create(); } $this->data[$key] = $objects; return $this; } $dataBuilder = $this->dataBuilderFactory->getDataBuilder($returnType); $object = $dataBuilder->populateWithArray($value)->create(); $this->data[$key] = $object; return $this; }
/** * Populate a specific attribute code with join directive instructions. * * @param string $attributeCode * @param array $directive * @param array &$data * @param array &$extensionData * @param string $extensibleEntityClass * @return void */ private function populateAttributeCodeWithDirective($attributeCode, $directive, &$data, &$extensionData, $extensibleEntityClass) { $attributeType = $directive[Converter::DATA_TYPE]; $selectFields = $this->joinProcessorHelper->getSelectFieldsMap($attributeCode, $directive[Converter::JOIN_FIELDS]); foreach ($selectFields as $selectField) { $internalAlias = $selectField[JoinDataInterface::SELECT_FIELD_INTERNAL_ALIAS]; if (isset($data[$internalAlias])) { if ($this->typeProcessor->isArrayType($attributeType)) { throw new \LogicException(sprintf('Join directives cannot be processed for attribute (%s) of extensible entity (%s),' . ' which has an Array type (%s).', $attributeCode, $this->extensionAttributesFactory->getExtensibleInterfaceName($extensibleEntityClass), $attributeType)); } elseif ($this->typeProcessor->isTypeSimple($attributeType)) { $extensionData['data'][$attributeCode] = $data[$internalAlias]; unset($data[$internalAlias]); break; } else { if (!isset($extensionData['data'][$attributeCode])) { $extensionData['data'][$attributeCode] = $this->objectManager->create($attributeType); } $setterName = $selectField[JoinDataInterface::SELECT_FIELD_SETTER]; $extensionData['data'][$attributeCode]->{$setterName}($data[$internalAlias]); unset($data[$internalAlias]); } } } }
/** * Return 'true' if $type is a simple type (string, int, ...). * * @param $type * @return bool */ public function isSimple($type) { $result = $this->_typeProcessor->isTypeSimple($type); return $result; }