/** * Creates a new instance of the given class and populates it with the array of data. The data can * be in different forms depending on the adapter being used, REST vs. SOAP. For REST, the data is * in snake_case (e.g. tax_class_id) while for SOAP the data is in camelCase (e.g. taxClassId). * * @param string $className * @param array $data * @return object the newly created and populated object * @throws \Exception */ protected function _createFromArray($className, $data) { $data = is_array($data) ? $data : []; $class = new ClassReflection($className); if (is_subclass_of($className, self::EXTENSION_ATTRIBUTES_TYPE)) { $className = substr($className, 0, -strlen('Interface')); } $object = $this->objectManager->create($className); foreach ($data as $propertyName => $value) { // Converts snake_case to uppercase CamelCase to help form getter/setter method names // This use case is for REST only. SOAP request data is already camel cased $camelCaseProperty = SimpleDataObjectConverter::snakeCaseToUpperCamelCase($propertyName); $methodName = $this->typeProcessor->findGetterMethodName($class, $camelCaseProperty); $methodReflection = $class->getMethod($methodName); if ($methodReflection->isPublic()) { $returnType = $this->typeProcessor->getGetterReturnType($methodReflection)['type']; try { $setterName = $this->typeProcessor->findSetterMethodName($class, $camelCaseProperty); } catch (\Exception $e) { if (empty($value)) { continue; } else { throw $e; } } if ($camelCaseProperty === 'CustomAttributes') { $setterValue = $this->convertCustomAttributeValue($value, $className); } else { $setterValue = $this->convertValue($value, $returnType); } $object->{$setterName}($setterValue); } } return $object; }
/** * Process generally coded methods ("public function getProp()"). * * @param string $type Normalized type name. * @param \Zend\Code\Reflection\MethodReflection[] $methods Reflection of the type's methods. */ public function _processMethods($type, $methods) { foreach ($methods as $method) { $methodName = $method->getName(); $isGetter = strpos($methodName, 'get') === 0; $hasParams = $method->getNumberOfParameters() > 0; $isIterator = $methodName == 'getIterator'; /* only getters w/o parameters will be proceeded */ if ($isGetter && !$hasParams && !$isIterator) { $propName = lcfirst(substr($methodName, 3)); $typeData = $this->_typeProcessor->getGetterReturnType($method); $propType = $typeData['type']; $propIsRequired = $typeData['isRequired']; $propIsArray = $this->_toolsType->isArray($propType); $propType = $this->_toolsType->normalizeType($propType); $propData = new \Praxigento\Core\Reflection\Data\Property(); $propData->setName($propName); $propData->setIsRequired($propIsRequired); $propData->setIsArray($propIsArray); $propData->setType($propType); $this->_registry[$type][$propName] = $propData; $this->register($propType); } } }
/** * Retrieve method info * * @param \ReflectionMethod $method * @return array */ protected function _getMethodInfo(\ReflectionMethod $method) { if (substr($method->getName(), 0, 2) == 'is') { $propertyName = substr($method->getName(), 2); } else { $propertyName = substr($method->getName(), 3); } $returnType = $this->typeProcessor->getGetterReturnType((new ClassReflection($this->_getSourceClassName()))->getMethod($method->getName())); $fieldName = strtolower(preg_replace('/(.)([A-Z])/', "\$1_\$2", $propertyName)); $methodInfo = ['name' => 'set' . $propertyName, 'parameters' => [['name' => lcfirst($propertyName)]], 'body' => "\$this->_set('{$fieldName}', \$" . lcfirst($propertyName) . ");" . PHP_EOL . "return \$this;", 'docblock' => ['tags' => [['name' => 'param', 'description' => $returnType['type'] . " \$" . lcfirst($propertyName)], ['name' => 'return', 'description' => '$this']]]]; return $methodInfo; }
/** * Retrieve method interface and documentation description. * * @param \Zend\Code\Reflection\MethodReflection $method * @return array * @throws \InvalidArgumentException */ public function extractMethodData(\Zend\Code\Reflection\MethodReflection $method) { $methodData = ['documentation' => $this->extractMethodDescription($method), 'interface' => []]; /** @var \Zend\Code\Reflection\ParameterReflection $parameter */ foreach ($method->getParameters() as $parameter) { $parameterData = ['type' => $this->_typeProcessor->register($this->_typeProcessor->getParamType($parameter)), 'required' => !$parameter->isOptional(), 'documentation' => $this->_typeProcessor->getParamDescription($parameter)]; if ($parameter->isOptional()) { $parameterData['default'] = $parameter->getDefaultValue(); } $methodData['interface']['in']['parameters'][$parameter->getName()] = $parameterData; } $returnType = $this->_typeProcessor->getGetterReturnType($method); if ($returnType != 'void' && $returnType != 'null') { $methodData['interface']['out']['parameters']['result'] = ['type' => $this->_typeProcessor->register($returnType['type']), 'documentation' => $returnType['description'], 'required' => true]; } return $methodData; }
/** * Use reflection to load the method information * * @param string $interfaceName * @return array */ private function getMethodMapViaReflection($interfaceName) { $methodMap = []; $class = new ClassReflection($interfaceName); $baseClassMethods = false; foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { // Include all the methods of classes inheriting from AbstractExtensibleObject. // Ignore all the methods of AbstractExtensibleModel's parent classes if ($method->class === self::BASE_MODEL_CLASS) { $baseClassMethods = true; } elseif ($baseClassMethods) { // ReflectionClass::getMethods() sorts the methods by class (lowest in inheritance tree first) // then by the order they are defined in the class definition break; } if ($this->isSuitableMethod($method)) { $methodMap[$method->getName()] = $this->typeProcessor->getGetterReturnType($method); } } return $methodMap; }
/** * Creates a new instance of the given class and populates it with the array of data. The data can * be in different forms depending on the adapter being used, REST vs. SOAP. For REST, the data is * in snake_case (e.g. tax_class_id) while for SOAP the data is in camelCase (e.g. taxClassId). * * @param string $className * @param array $data * @return object the newly created and populated object */ protected function _createFromArray($className, $data) { $data = is_array($data) ? $data : []; $class = new ClassReflection($className); $builder = $this->builderFactory->getDataBuilder($className); foreach ($data as $propertyName => $value) { // Converts snake_case to uppercase CamelCase to help form getter/setter method names // This use case is for REST only. SOAP request data is already camel cased $camelCaseProperty = SimpleDataObjectConverter::snakeCaseToUpperCamelCase($propertyName); $methodName = $this->typeProcessor->findGetterMethodName($class, $camelCaseProperty); $methodReflection = $class->getMethod($methodName); if ($methodReflection->isPublic()) { $returnType = $this->typeProcessor->getGetterReturnType($methodReflection)['type']; $setterName = 'set' . $camelCaseProperty; if ($camelCaseProperty === 'CustomAttributes') { $setterValue = $this->convertCustomAttributeValue($value, $returnType, $className); } else { $setterValue = $this->_convertValue($value, $returnType); } $builder->{$setterName}($setterValue); } } return $builder->create(); }