* @license http://www.apache.org/licenses/LICENSE-2.0 * @link http://phpsx.org */ class Annotation implements ParserInterface { /** @var \Doctrine\Common\Annotations\Reader */ private $annotationReader; /** @var \PSX\Schema\SchemaManagerInterface */ private $schemaManager; /** * @param \Doctrine\Common\Annotations\Reader $annotationReader * @param \PSX\Schema\SchemaManagerInterface $schemaManager */ public function __construct(Reader $annotationReader, SchemaManagerInterface $schemaManager) { $this->annotationReader = $annotationReader; $this->schemaManager = $schemaManager; } /** * @inheritdoc */ public function parse(string $schema, ?string $path = null): SpecificationInterface { if (!is_string($schema)) { throw new RuntimeException('Schema must be a class name'); } $resource = new Resource(Resource::STATUS_ACTIVE, $path); $definitions = new Definitions(); $controller = new ReflectionClass($schema); $basePath = dirname($controller->getFileName()); $required = []; $annotations = $this->annotationReader->getClassAnnotations($controller); $path = TypeFactory::getStruct(); foreach ($annotations as $annotation) { if ($annotation instanceof Anno\Title) { $resource->setTitle($annotation->getTitle()); } elseif ($annotation instanceof Anno\Description) { $resource->setDescription($this->getDescription($annotation, $basePath)); } elseif ($annotation instanceof Anno\PathParam) { $required[] = $annotation->getName(); $path->addProperty($annotation->getName(), $this->getParameter($annotation)); } } if ($path->getProperties()) { $typeName = 'Path'; $path->setRequired($required); $definitions->addType($typeName, $path); $resource->setPathParameters($typeName); } $this->parseMethods($controller, $resource, $definitions, $basePath); return Specification::fromResource($resource, $definitions); } /** * @param \ReflectionClass $controller * @param \PSX\Api\Resource $resource * @param DefinitionsInterface $definitions * @param string $basePath */ private function parseMethods( ReflectionClass $controller, Resource $resource, DefinitionsInterface $definitions, $basePath, ) { $methods = [ 'GET' => 'doGet', 'POST' => 'doPost', 'PUT' => 'doPut', 'DELETE' => 'doDelete', 'PATCH' => 'doPatch' ]; foreach ($methods as $httpMethod => $methodName) { // check whether method exists if (!$controller->hasMethod($methodName)) { continue; } $method = Resource\Factory::getMethod($httpMethod); $reflection = $controller->getMethod($methodName); $required = []; $annotations = $this->annotationReader->getMethodAnnotations($reflection); $method->setOperationId($reflection->getName()); $query = TypeFactory::getStruct(); $typePrefix = str_replace('\\', '', $controller->getName()) . ucfirst(strtolower($httpMethod)); foreach ($annotations as $annotation) { if ($annotation instanceof Anno\Description) { $method->setDescription($this->getDescription($annotation, $basePath)); } elseif ($annotation instanceof Anno\QueryParam) { if ($annotation->isRequired()) { $required[] = $annotation->getName(); } $query->addProperty($annotation->getName(), $this->getParameter($annotation)); } elseif ($annotation instanceof Anno\Incoming) { $schema = $this->getBodySchema($annotation, $definitions, $basePath, $typePrefix . 'Request'); if (!empty($schema)) { $method->setRequest($schema); } } elseif ($annotation instanceof Anno\Outgoing) { $schema = $this->getBodySchema($annotation, $definitions, $basePath, $typePrefix . $annotation->getCode() . 'Response'); if (!empty($schema)) { $method->addResponse($annotation->getCode(), $schema); } } elseif ($annotation instanceof Anno\Exclude) { // skip this method continue 2; } } if ($query->getProperties()) { $typeName = ucfirst(strtolower($methodName)) . 'Query'; $query->setRequired($required); $definitions->addType($typeName, $query); $method->setQueryParameters($typeName); } $resource->addMethod($method); } } private function getBodySchema( Anno\SchemaAbstract $annotation, DefinitionsInterface $definitions, string $basePath, string $typeName, ): string { $schema = $annotation->getSchema(); $type = $annotation->getType(); // if we have a file append base path if (strpos($schema, '.') !== false) { $type = SchemaManager::TYPE_TYPESCHEMA; $schema = $basePath . '/' . $schema; } $schema = $this->schemaManager->getSchema($schema, $type); $definitions->addSchema($typeName, $schema); return $typeName; } private function getDescription(Anno\Description $annotation, $basePath) { $description = $annotation->getDescription(); if (substr($description, 0, 8) === '!include') { $file = $basePath . '/' . trim(substr($description, 9)); if (is_file($file)) { return file_get_contents($file); } else { throw new RuntimeException('Could not include file ' . $file); } } else { return $description; } } private function getParameter(Anno\ParamAbstract $param): TypeInterface { switch ($param->getType()) { case 'integer': $type = TypeFactory::getInteger(); break; case 'number': $type = TypeFactory::getNumber(); break; case 'boolean': $type = TypeFactory::getBoolean(); break; case 'string': default: $type = TypeFactory::getString(); break; } if ($type instanceof TypeAbstract) { $description = $param->getDescription(); if ($description !== null) { $type->setDescription($description); } } if ($type instanceof ScalarType) { $enum = $param->getEnum(); if ($enum !== null && is_array($enum)) { $type->setEnum($enum); } } if ($type instanceof StringType) { $minLength = $param->getMinLength(); if ($minLength !== null) { $type->setMinLength($minLength); } $maxLength = $param->getMaxLength(); if ($maxLength !== null) { $type->setMaxLength($maxLength); } $pattern = $param->getPattern(); if ($pattern !== null) { $type->setPattern($pattern); } $format = $param->getFormat(); if ($format !== null) { $type->setFormat($format); } } elseif ($type instanceof NumberType) { $minimum = $param->getMinimum(); if ($minimum !== null) { $type->setMinimum($minimum); } $maximum = $param->getMaximum(); if ($maximum !== null) { $type->setMaximum($maximum); } $multipleOf = $param->getMultipleOf(); if ($multipleOf !== null) { $type->setMultipleOf($multipleOf); } } return $type; } } __halt_compiler();----SIGNATURE:----ba0KLToGRCDfp8lGsAji/ztGb203db4LJnPAL9GCWo7KVtc4zxL609yfIBXWQLnG9uSp84yxAiGsNpjKagBdA5lV/ZBQizAuDgU8Kd1ps+pX4WP8q1WlRNeHYodPozeX74KuoshhT/dpg4GVk5VZjvzdI+9s/u7fPRt8nIqHbhxuMQaMcJAbJEMcUXy9gkdmUV/XFaxTgo/S7Rj233XEO2xFDSu/hRrlKX896teYS3Gvlg0oFD/wBAH+N4dfoOej+2tUjGQoiy1sWUjZ8cC1Z5J5pgaslz/ILRgEwL9Wa/O15ZNRyvmpTlmvcwsVsK/IUqpHePVMmrXVWD6gf5r0vPTcuSrPwqRt5CzYPIZJca+KrClg1VTE3aFWghUi2XuANl2PpXeLE/j4NcTxQqHhAmnc/Za8hYx8e3uxq6PL6yLjC/tIqCvMPgahP1n5bs2S8wp5jpdhu/SQf98kVjVEzVPTqUussXBmH1Dp+J6sPuzK894sLLEW/xk/eUcGsVgPIRg1PA70+p8j5RnumoDgmZe2IPhYrpJ0t8SyYLCuKubXUHW6C5DmQdW4iE0O9zW6WzJr/0D8AJiqqWKQ/+m1n/YCMVzwwmiu28w5E3L4IBY28IXEGn61/U7cTHluo5KUYlUTF0r9lAsTQjy17gdByFWiTOswbtYYg8z44bD6g1g=----ATTACHMENT:----OTcyMTQ3MzE1ODcyNjk0MyA2NDA3OTg2NzcwNzEwNzU5IDgzNDU5MjIyOTYzOTU3NjI=