11 use Zend\Code\Reflection\ClassReflection;
12 use Zend\Code\Reflection\DocBlock\Tag\ParamTag;
13 use Zend\Code\Reflection\DocBlock\Tag\ReturnTag;
14 use Zend\Code\Reflection\DocBlockReflection;
15 use Zend\Code\Reflection\MethodReflection;
16 use Zend\Code\Reflection\ParameterReflection;
61 private function getNameFinder()
63 if ($this->nameFinder ===
null) {
65 ->get(\
Magento\Framework\Reflection\NameFinder::class);
67 return $this->nameFinder;
90 $this->_types = $typesData;
103 if (!isset($this->_types[$typeName])) {
104 throw new \InvalidArgumentException(
105 sprintf(
'The "%s" data type isn\'t declared. Verify the type and try again.', $typeName)
108 return $this->_types[$typeName];
120 if (!isset($this->_types[$typeName])) {
121 $this->_types[$typeName] =
$data;
123 $this->_types[$typeName] = array_merge_recursive($this->_types[$typeName],
$data);
137 if (
null === $typeName) {
142 if (!(
class_exists($typeSimple) || interface_exists($typeSimple))) {
143 throw new \LogicException(
145 'The "%s" class doesn\'t exist and the namespace must be specified. Verify and try again.',
151 if (!isset($this->_types[$complexTypeName])) {
152 $this->_processComplexType(
$type);
154 $typeName = $complexTypeName;
168 protected function _processComplexType(
$class)
171 $this->_types[$typeName] = [];
176 throw new \InvalidArgumentException(
177 sprintf(
'The "%s" class couldn\'t load as a parameter type.',
$class)
180 $reflection =
new ClassReflection(
$class);
181 $docBlock = $reflection->getDocBlock();
182 $this->_types[$typeName][
'documentation'] = $docBlock ? $this->
getDescription($docBlock) :
'';
184 foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $methodReflection) {
185 if ($methodReflection->class === \
Magento\Framework\Model\AbstractModel::class) {
192 return $this->_types[$typeName];
204 $isGetter = (strpos($methodReflection->getName(),
'get') === 0)
205 || (strpos($methodReflection->getName(),
'is') === 0)
206 || (strpos($methodReflection->getName(),
'has') === 0);
208 if ($isGetter && !$methodReflection->getNumberOfRequiredParameters()) {
210 $fieldName = $this->getNameFinder()->getFieldNameFromGetterName($methodReflection->getName());
211 if ($returnMetadata[
'description']) {
214 $description = $this->getNameFinder()->getFieldDescriptionFromGetterDescription(
215 $methodReflection->getDocBlock()->getShortDescription()
218 $this->_types[$typeName][
'parameters'][$fieldName] = [
219 'type' => $this->
register($returnMetadata[
'type']),
220 'required' => $returnMetadata[
'isRequired'],
234 $shortDescription = $doc->getShortDescription();
235 $longDescription = $doc->getLongDescription();
238 $longDescription = str_replace([
"\n",
"\r"],
'', $longDescription);
257 return $this->getNameFinder()->getFieldNameFromGetterName($getterName);
270 return $this->getNameFinder()->getFieldDescriptionFromGetterDescription($shortDescription);
287 $returnAnnotation = $this->getMethodReturnAnnotation($methodReflection);
288 $types = $returnAnnotation->getTypes();
289 $returnType = current($types);
290 $nullable = in_array(
'null', $types);
293 'type' => $returnType,
294 'isRequired' => !$nullable,
295 'description' => $returnAnnotation->getDescription(),
296 'parameterCount' => $methodReflection->getNumberOfRequiredParameters()
306 public function getExceptions($methodReflection)
309 $methodDocBlock = $methodReflection->getDocBlock();
310 if ($methodDocBlock->hasTag(
'throws')) {
311 $throwsTypes = $methodDocBlock->getTags(
'throws');
312 if (is_array($throwsTypes)) {
314 foreach ($throwsTypes as $throwsType) {
315 $exceptions = array_merge($exceptions, $throwsType->getTypes());
331 if (
$type ==
'null') {
334 $normalizationMap = [
353 $this->getNormalizedType(
$type),
355 self::NORMALIZED_STRING_TYPE,
356 self::NORMALIZED_INT_TYPE,
357 self::NORMALIZED_FLOAT_TYPE,
358 self::NORMALIZED_DOUBLE_TYPE,
359 self::NORMALIZED_BOOLEAN_TYPE,
372 return ($this->getNormalizedType(
$type) == self::NORMALIZED_ANY_TYPE);
388 return (
bool)preg_match(
'/(\[\]$|^ArrayOf)/',
$type);
411 return $this->
normalizeType(str_replace(
'[]',
'', $arrayType));
428 if (preg_match(
'/\\\\?(.*)\\\\(.*)\\\\(Service|Api)\\\\\2?(.*)/',
$class, $matches)) {
429 $moduleNamespace = $matches[1] ==
'Magento' ?
'' : $matches[1];
430 $moduleName = $matches[2];
431 $typeNameParts = explode(
'\\', $matches[4]);
433 return ucfirst($moduleNamespace . $moduleName . implode(
'', $typeNameParts));
435 throw new \InvalidArgumentException(
436 sprintf(
'The "%s" parameter type is invalid. Verify the parameter and try again.',
$class)
470 if ($isArrayType && is_array(
$value)) {
472 foreach (array_keys(
$value) as $key) {
473 if (
$value !==
null && !settype(
$value[$key], $arrayItemType)) {
476 'The "%value" value\'s type is invalid. The "%type" type was expected. ' 477 .
'Verify and try again.',
489 'The "%value" value\'s type is invalid. The "%type" type was expected. Verify and try again.',
497 'The "%value" value\'s type is invalid. The "%type" type was expected. Verify and try again.',
514 $type = $param->detectType();
515 if (
$type ==
'null') {
516 throw new \LogicException(sprintf(
517 '@param annotation is incorrect for the parameter "%s" in the method "%s:%s".' 518 .
' First declared type should not be null. E.g. string|null',
520 $param->getDeclaringClass()->getName(),
521 $param->getDeclaringFunction()->name
524 if (
$type ==
'array') {
526 $paramDocBlock = $this->getParamDocBlockTag($param);
527 $paramTypes = $paramDocBlock->getTypes();
528 $paramType = array_shift($paramTypes);
529 return strpos($paramType,
'[]') !==
false ? $paramType :
"{$paramType}[]";
542 $paramDocBlock = $this->getParamDocBlockTag($param);
543 return $paramDocBlock->getDescription();
558 return $this->getNameFinder()->getGetterMethodName(
$class, $camelCaseProperty);
572 $booleanTypes = [
'bool',
'boolean'];
573 if (in_array(
$type, $booleanTypes)) {
577 $numType = [
'int',
'float'];
578 if (in_array(
$type, $numType) && !is_numeric(
$value)) {
596 return $this->getNameFinder()->getSetterMethodName(
$class, $camelCaseProperty);
617 return $this->getNameFinder()
618 ->findAccessorMethodName(
$class, $camelCaseProperty, $accessorName, $boolAccessorName);
634 return $this->getNameFinder()->hasMethod(
$class, $methodName);
648 foreach ($interface as $direction => $interfaceData) {
649 $direction = ($direction ==
'in') ?
'requiredInput' :
'returned';
650 if ($direction ==
'returned' && !isset($interfaceData[
'parameters'])) {
654 foreach ($interfaceData[
'parameters'] as $parameterData) {
657 if ($parameterData[
'required']) {
658 $condition = ($direction ==
'requiredInput') ?
'yes' :
'always';
660 $condition = ($direction ==
'requiredInput') ?
'no' :
'conditionally';
663 $callInfo[$direction][$condition][
'calls'][] = $operation;
664 $this->
setTypeData($parameterData[
'type'], [
'callInfo' => $callInfo]);
680 return $serviceName . ucfirst($methodName);
689 private function getNormalizedType(
$type)
705 private function getMethodReturnAnnotation(MethodReflection $methodReflection)
707 $methodName = $methodReflection->getName();
708 $returnAnnotations = $this->getReturnFromDocBlock($methodReflection);
709 if (empty($returnAnnotations)) {
711 $implemented = $methodReflection->getDeclaringClass()->getInterfaces();
713 foreach ($implemented as $parentClassReflection) {
714 if ($parentClassReflection->hasMethod($methodName)) {
715 $returnAnnotations = $this->getReturnFromDocBlock(
716 $parentClassReflection->getMethod($methodName)
722 if (empty($returnAnnotations)) {
723 throw new \InvalidArgumentException(
724 "Method's return type must be specified using @return annotation. " 725 .
"See {$methodReflection->getDeclaringClass()->getName()}::{$methodName}()" 729 return $returnAnnotations;
738 private function getReturnFromDocBlock(MethodReflection $methodReflection)
740 $methodDocBlock = $methodReflection->getDocBlock();
741 if (!$methodDocBlock) {
742 throw new \InvalidArgumentException(
743 "Each method must have a doc block. " 744 .
"See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" 747 return current($methodDocBlock->getTags(
'return'));
756 private function getParamDocBlockTag(ParameterReflection $param): ParamTag
758 $docBlock = $param->getDeclaringFunction()
760 $paramsTag = $docBlock->getTags(
'param');
761 return $paramsTag[$param->getPosition()];
elseif(isset( $params[ 'redirect_parent']))
isValidTypeDeclaration($type)
findSetterMethodName(ClassReflection $class, $camelCaseProperty)
dataObjectGetterDescriptionToFieldDescription($shortDescription)
translateTypeName($class)
const NORMALIZED_INT_TYPE
const NORMALIZED_ANY_TYPE
getGetterReturnType($methodReflection)
processInterfaceCallInfo($interface, $serviceName, $methodName)
const NORMALIZED_BOOLEAN_TYPE
processSimpleAndAnyType($value, $type)
dataObjectGetterNameToFieldName($getterName)
findAccessorMethodName(ClassReflection $class, $camelCaseProperty, $accessorName, $boolAccessorName)
$_option $_optionId $class
const NORMALIZED_DOUBLE_TYPE
getParamType(ParameterReflection $param)
const NORMALIZED_STRING_TYPE
classHasMethod(ClassReflection $class, $methodName)
getOperationName($serviceName, $methodName)
const NORMALIZED_FLOAT_TYPE
getArrayItemType($arrayType)
findGetterMethodName(ClassReflection $class, $camelCaseProperty)
getDescription(DocBlockReflection $doc)
getParamDescription(ParameterReflection $param)
setTypeData($typeName, $data)
_processMethod(MethodReflection $methodReflection, $typeName)
translateArrayTypeName($type)