/** * @param MethodReflection $reflectionMethod * @return MethodGenerator */ public static function fromReflection(MethodReflection $reflectionMethod) { $method = new static(); $declaringClass = $reflectionMethod->getDeclaringClass(); $method->setSourceContent($reflectionMethod->getContents(false)); $method->setSourceDirty(false); if ($reflectionMethod->getDocComment() != '') { $method->setDocBlock(DocBlockGenerator::fromReflection($reflectionMethod->getDocBlock())); } $method->setFinal($reflectionMethod->isFinal()); if ($reflectionMethod->isPrivate()) { $method->setVisibility(self::VISIBILITY_PRIVATE); } elseif ($reflectionMethod->isProtected()) { $method->setVisibility(self::VISIBILITY_PROTECTED); } else { $method->setVisibility(self::VISIBILITY_PUBLIC); } $method->setInterface($declaringClass->isInterface()); $method->setStatic($reflectionMethod->isStatic()); $method->setName($reflectionMethod->getName()); foreach ($reflectionMethod->getParameters() as $reflectionParameter) { $method->setParameter(ParameterGenerator::fromReflection($reflectionParameter)); } $method->setBody(static::clearBodyIndention($reflectionMethod->getBody())); return $method; }
/** @inheritdoc */ protected function _processMethod(\Zend\Code\Reflection\MethodReflection $methodReflection, $typeName) { /* skip basic methods of the DataObjects */ $name = $methodReflection->getName(); if ($name != self::SKIP_DATA && $name != self::SKIP_ITERATOR && $name != self::SKIP_DATA_UNSET) { parent::_processMethod($methodReflection, $typeName); } }
/** * Process method parameters * * @param array $def * @param Reflection\ClassReflection $rClass * @param Reflection\MethodReflection $rMethod */ protected function processParams(&$def, Reflection\ClassReflection $rClass, Reflection\MethodReflection $rMethod) { if (count($rMethod->getParameters()) === 0) { return; } $methodName = $rMethod->getName(); // @todo annotations here for alternate names? $def['parameters'][$methodName] = array(); foreach ($rMethod->getParameters() as $p) { /** @var $p \ReflectionParameter */ $actualParamName = $p->getName(); $fqName = $rClass->getName() . '::' . $rMethod->getName() . ':' . $p->getPosition(); $def['parameters'][$methodName][$fqName] = array(); // set the class name, if it exists $def['parameters'][$methodName][$fqName][] = $actualParamName; $def['parameters'][$methodName][$fqName][] = $p->getClass() !== null ? $p->getClass()->getName() : null; $def['parameters'][$methodName][$fqName][] = !$p->isOptional(); $def['parameters'][$methodName][$fqName][] = $p->isOptional() && $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null; } }
/** * @return MethodGenerator */ private function generateProxyMethod(\ReflectionMethod $method, $preSource, $postSource, $exceptionSource) { $methodReflection = new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()); if ('__construct' === $methodReflection->getName()) { $methodGenerator = MethodGenerator::fromArray(['name' => $methodReflection->getName(), 'body' => '']); } else { $methodGenerator = MethodGenerator::fromReflection($methodReflection); $parametersString = '('; $i = count($method->getParameters()); foreach ($method->getParameters() as $parameter) { $parametersString .= '$' . $parameter->getName() . (--$i > 0 ? ',' : ''); } $parametersString .= ')'; if ('' === $preSource && '' === $postSource && '' === $exceptionSource) { $body = 'return $this->proxy_realSubject->' . $method->getName() . $parametersString . ";\n"; } else { $body = "try {\n" . $preSource . "\n" . '$data = $this->proxy_realSubject->' . $method->getName() . $parametersString . ";\n" . $postSource . "\n" . "return \$data;\n" . "} catch(\\Exception \$e){\n" . $exceptionSource . "\n" . "throw \$e;\n" . '};'; } $methodGenerator->setBody($body); } return $methodGenerator; }
/** * Retrieve method full documentation description. * * @param \Zend\Code\Reflection\MethodReflection $method * @return string */ protected function extractMethodDescription(\Zend\Code\Reflection\MethodReflection $method) { $methodReflection = new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()); $docBlock = $methodReflection->getDocBlock(); if (!$docBlock) { throw new \LogicException('The docBlock of the method ' . $method->getDeclaringClass()->getName() . '::' . $method->getName() . ' is empty.'); } return $this->_typeProcessor->getDescription($docBlock); }
/** * Identify getter return type by its reflection. * * @param \Zend\Code\Reflection\MethodReflection $methodReflection * @return array <pre>array( * 'type' => <string>$type, * 'isRequired' => $isRequired, * 'description' => $description * )</pre> * @throws \InvalidArgumentException */ public function getGetterReturnType($methodReflection) { $methodDocBlock = $methodReflection->getDocBlock(); if (!$methodDocBlock) { throw new \InvalidArgumentException("Each getter must have description with @return annotation. " . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()"); } $returnAnnotations = $methodDocBlock->getTags('return'); if (empty($returnAnnotations)) { throw new \InvalidArgumentException("Getter return type must be specified using @return annotation. " . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()"); } /** @var \Zend\Code\Reflection\DocBlock\Tag\ReturnTag $returnAnnotation */ $returnAnnotation = current($returnAnnotations); $returnType = $returnAnnotation->getType(); /* * Adding this code as a workaround since \Zend\Code\Reflection\DocBlock\Tag\ReturnTag::initialize does not * detect and return correct type for array of objects in annotation. * eg @return \Magento\Webapi\Service\Entity\SimpleData[] is returned with type * \Magento\Webapi\Service\Entity\SimpleData instead of \Magento\Webapi\Service\Entity\SimpleData[] */ $escapedReturnType = str_replace('[]', '\\[\\]', $returnType); $escapedReturnType = str_replace('\\', '\\\\', $escapedReturnType); if (preg_match("/.*\\@return\\s+({$escapedReturnType}).*/i", $methodDocBlock->getContents(), $matches)) { $returnType = $matches[1]; } $isRequired = preg_match("/.*\\@return\\s+\\S+\\|null.*/i", $methodDocBlock->getContents(), $matches) ? false : true; return ['type' => $returnType, 'isRequired' => $isRequired, 'description' => $returnAnnotation->getDescription(), 'parameterCount' => $methodReflection->getNumberOfRequiredParameters()]; }
/** * Collect metadata for virtual field corresponding to current method if it is a getter (used in WSDL generation). * * @param \Zend\Code\Reflection\MethodReflection $methodReflection * @param string $typeName * @return void */ protected function _processMethod(\Zend\Code\Reflection\MethodReflection $methodReflection, $typeName) { $isGetter = strpos($methodReflection->getName(), 'get') === 0 || strpos($methodReflection->getName(), 'is') === 0 || strpos($methodReflection->getName(), 'has') === 0; /** Field will not be added to WSDL if getter has params */ if ($isGetter && !$methodReflection->getNumberOfParameters()) { $returnMetadata = $this->getGetterReturnType($methodReflection); $fieldName = $this->dataObjectGetterNameToFieldName($methodReflection->getName()); $this->_types[$typeName]['parameters'][$fieldName] = array('type' => $this->process($returnMetadata['type']), 'required' => $returnMetadata['isRequired'], 'documentation' => $returnMetadata['description']); } }
/** * Retrieve method name * * @return string */ public function getName() { return $this->reflection->getName(); }
/** * Tries to guess default values for route if there some missing ones. * * @param Route $annotation * @param MethodReflection $method * @param string $controllerKey * @return Route * @throws Exception */ public function autodetectMissingFields(Route $annotation, $method, $controllerKey) { if ($method instanceof MethodReflection) { $methodName = $method->getName(); } else { if (is_string($method)) { $methodName = $method; } else { throw new Exception('Method must be a string or instance of MethodReflection'); } } if (!$annotation->hasName()) { $annotation->setName($this->filterActionMethodName($methodName)); } if (!$annotation->hasType()) { $annotation->setType('literal'); } if (!$annotation->hasDefaultController()) { $annotation->setDefaultController($controllerKey); } if (!$annotation->hasDefaultAction()) { $annotation->setDefaultAction($this->filterActionMethodName($methodName)); } if (!$annotation->hasRoute()) { $annotation->setRoute('/' . $this->filterActionMethodName($methodName)); } return $annotation; }