* @license http://www.apache.org/licenses/LICENSE-2.0 * @link http://phpsx.org */ class OpenAPI extends OpenAPIAbstract { /** * @inheritDoc */ public function generate(SpecificationInterface $specification) { $collection = $specification->getResourceCollection(); $definitions = $specification->getDefinitions(); $removeTypes = []; $paths = new Paths(); foreach ($collection as $path => $resource) { $this->buildPaths($resource, $paths, $definitions, $removeTypes); } // the definitions contain types for path and query parameters which we can remove foreach ($removeTypes as $type) { $definitions->removeType($type); } return $this->buildDeclaration($paths, $definitions); } /** * @param \PSX\Model\OpenAPI\Paths $paths * @param \PSX\Schema\DefinitionsInterface $definitions * @return string */ protected function buildDeclaration(Paths $paths, DefinitionsInterface $definitions) { $info = new Info(); $info->setTitle($this->title ?: 'PSX'); $info->setDescription($this->description); $info->setTermsOfService($this->tos); if (!empty($this->contactName)) { $contact = new Contact(); $contact->setName($this->contactName); $contact->setUrl($this->contactUrl); $contact->setEmail($this->contactEmail); $info->setContact($contact); } if (!empty($this->licenseName)) { $license = new License(); $license->setName($this->licenseName); $license->setUrl($this->licenseUrl); $info->setLicense($license); } $info->setVersion($this->apiVersion); $server = new Server(); $server->setUrl($this->baseUri); $generator = new Generator\JsonSchema('#/components/schemas/'); $result = $generator->toArray(TypeFactory::getAny(), $definitions); $schemas = new Schemas(); foreach ($result['definitions'] as $name => $schema) { $schemas[$name] = $schema; } $components = new Components(); $components->setSchemas($schemas); $this->buildSecuritySchemes($components); $openAPI = new Declaration(); $openAPI->setInfo($info); $openAPI->setServers([$server]); $openAPI->setPaths($paths); $openAPI->setComponents($components); if (!empty($this->tags)) { $openAPI->setTags($this->tags); } $data = $this->dumper->dump($openAPI); $data = Parser::encode($data, JSON_PRETTY_PRINT); return $data; } /** * @param \PSX\Model\OpenAPI\Components $components */ protected function buildSecuritySchemes(Components $components) { $schemes = new SecuritySchemes(); foreach ($this->authFlows as $authName => $authFlows) { $flows = new OAuthFlows(); foreach ($authFlows as $authFlow) { [$flowType, $authorizationUrl, $tokenUrl, $refreshUrl, $scopes] = $authFlow; $flow = new OAuthFlow(); $flow->setAuthorizationUrl($authorizationUrl); $flow->setTokenUrl($tokenUrl); if (!empty($refreshUrl)) { $flow->setRefreshUrl($refreshUrl); } if (!empty($scopes)) { $result = new Scopes(); foreach ($scopes as $name => $title) { $result[$name] = $title; } $flow->setScopes($result); } if ($flowType == self::FLOW_AUTHORIZATION_CODE) { $flows->setAuthorizationCode($flow); } elseif ($flowType == self::FLOW_IMPLICIT) { $flows->setImplicit($flow); } elseif ($flowType == self::FLOW_PASSWORD) { $flows->setPassword($flow); } elseif ($flowType == self::FLOW_CLIENT_CREDENTIALS) { $flows->setClientCredentials($flow); } } $scheme = new SecurityScheme(); $scheme->setType('oauth2'); $scheme->setFlows($flows); $schemes[$authName] = $scheme; } if (count($schemes->getProperties()) > 0) { $components->setSecuritySchemes($schemes); } } /** * @param \PSX\Api\Resource $resource * @param \PSX\Model\OpenAPI\Paths $paths * @param \PSX\Schema\DefinitionsInterface $definitions */ protected function buildPaths( Resource $resource, Paths $paths, DefinitionsInterface $definitions, array &$removeTypes, ) { $path = new PathItem(); // path parameter $pathParameters = $resource->getPathParameters(); if (!empty($pathParameters) && $definitions->hasType($pathParameters)) { $parameters = $this->newParameters($definitions->getType($pathParameters), 'path', $definitions); if (!empty($parameters)) { $path->setParameters($parameters); $removeTypes[] = $pathParameters; } } $methods = $resource->getMethods(); foreach ($methods as $method) { $operation = new Operation(); // operation $operationId = $method->getOperationId(); if (!empty($operationId)) { $operation->setOperationId($operationId); } // description $description = $method->getDescription(); if (!empty($description)) { $operation->setDescription($description); } // tags $tags = array_merge($resource->getTags(), $method->getTags()); if (!empty($tags)) { $operation->setTags($tags); } // query parameter $queryParameters = $method->getQueryParameters(); if (!empty($queryParameters) && $definitions->hasType($queryParameters)) { $parameters = $this->newParameters($definitions->getType($queryParameters), 'query', $definitions); if (!empty($parameters)) { $operation->setParameters($parameters); $removeTypes[] = $queryParameters; } } // request body $request = $method->getRequest(); if (!empty($request)) { $requestBody = new RequestBody(); $requestBody->setDescription($method->getName() . ' Request'); $requestBody->setContent($this->getMediaTypes($request)); $operation->setRequestBody($requestBody); } // response body $responses = $method->getResponses(); $resps = new Responses(); foreach ($responses as $statusCode => $response) { $resp = new Response(); $resp->setDescription($method->getName() . ' ' . $statusCode . ' Response'); $resp->setContent($this->getMediaTypes($response)); $resps[strval($statusCode)] = $resp; } $operation->setResponses($resps); // security $security = $method->getSecurity(); if (!empty($security)) { $operation->setSecurity([SecurityRequirement::fromArray($security)]); } // tags $tags = $method->getTags(); if (!empty($tags)) { $operation->setTags($tags); } if ($resource->getStatus() == Resource::STATUS_DEPRECATED) { $operation->setDeprecated(true); } if ($method->getName() === 'GET') { $path->setGet($operation); } elseif ($method->getName() === 'POST') { $path->setPost($operation); } elseif ($method->getName() === 'PUT') { $path->setPut($operation); } elseif ($method->getName() === 'DELETE') { $path->setDelete($operation); } elseif ($method->getName() === 'PATCH') { $path->setPatch($operation); } } $paths[Inflection::convertPlaceholderToCurly($resource->getPath())] = $path; } /** * @param TypeInterface $type * @param string $in * @return array */ private function newParameters(TypeInterface $type, string $in, DefinitionsInterface $definitions): array { if (!$type instanceof StructType) { return []; } $parameters = []; if ($type->getExtends() && $definitions->hasType($type->getExtends())) { $parameters = $this->newParameters($definitions->getType($type->getExtends()), $in, $definitions); } $properties = $type->getProperties(); if ($properties) { foreach ($properties as $name => $parameter) { $param = $this->newParameter($parameter, in_array($name, $type->getRequired() ?: [])); $param->setName($name); $param->setIn($in); $parameters[] = $param; } } return $parameters; } /** * @param \PSX\Schema\TypeInterface $type * @return \PSX\Model\OpenAPI\Parameter $param */ protected function newParameter(TypeInterface $type, $required) { $param = new Parameter(); $param->setDescription($type->getDescription()); $param->setRequired($required); $param->setSchema($type->toArray()); return $param; } /** * @inheritdoc */ protected function newTag(string $name, string $description) { $tag = new Tag(); $tag->setName($name); $tag->setDescription($description); return $tag; } private function getMediaTypes(string $type) { $mediaType = new MediaType(); $mediaType->setSchema((object) ['$ref' => '#/components/schemas/' . $type]); $mediaTypes = new MediaTypes(); $mediaTypes['application/json'] = $mediaType; return $mediaTypes; } } __halt_compiler();----SIGNATURE:----bilnLM3NAs5ddI2fT9lddXhsizCE3ONP6dEkEo0ehHNwOIo5Ty+SLDC04x6KS68fbfaJxp1m2BCb8W8Y5TmulD43UIO76e7pfgl+b+HMxa5Ax2xl/vO3YX1PnXh8r19U1lGTYkl597RihVDcB82mMjmM3aR0vM7HtBwqE8m7f7sWqnQokmpb0hmcnk/rVebt4nPXImKAZ3JkhH6RvLSWKf6wdNX5qw+cYWUzoBUJfOG7OkbX8zVEcpZ3XXY0G1lRxkBkiZBWmZb8t/Qd/FPT3/vyjzlLlVJYWwGingPj5s8kmITJq0On2795kSeQE/KNkjhWQf4JSXZOUAPcc/cw/4bQ7TORwSmn4yjz+OSksmZL+ynLs8tGjwofG0R8WUq+LCtvQm3O+c+2j6eG6go2MxWKuBCm895ToxD2TWWkR9pmohikHqW+ShxBCcaJKDIsmqAWVoHbUnl2fIPg2FpB8ochZFxddpBnph7mg0IcYfqiCITLI1sRaYs9at/Afj53hDqWCA5XoTSTU9XZp3wgPzN9dxOEfpOajeQaS94/vk3lHiOECqEOvBGKKZMylW0X0gGrN9uQPHdH/1/dGI6zebYbSnZwvRvjta9TxH6AYhL6fnD1VEcEQkWEv+Ag0Nf4geGIJbMX2DSkvq+n5WoUt5+6ZtOHmeZ8gJx3/Qd/fvU=----ATTACHMENT:----MzgxMjUwMzc1NjE0ODQ2MyA4Nzk3MzAwODA5NzE1MTkzIDIxOTAwMjk5NzM3NDEyMzU=