From fff2540b94e6fc9278dcd98f816114e01b87618d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 2 Mar 2021 08:17:31 +0100 Subject: [PATCH 01/20] Add factory interfaces --- .../RequestBodies/CreatePetRequestBody.php | 27 +++++++++++++++++ examples/petstore/PetController.php | 10 +++++++ src/Attributes/Callback.php | 8 ++--- src/Attributes/Extension.php | 8 ++--- src/Attributes/Parameters.php | 8 ++--- src/Attributes/RequestBody.php | 8 ++--- src/Attributes/Response.php | 8 ++--- src/Builders/Components/CallbacksBuilder.php | 6 ++-- .../Components/RequestBodiesBuilder.php | 6 ++-- src/Builders/Components/ResponsesBuilder.php | 6 ++-- src/Builders/Components/SchemasBuilder.php | 6 ++-- .../Components/SecuritySchemesBuilder.php | 6 ++-- src/Builders/ExtensionsBuilder.php | 4 +-- .../Paths/Operation/ParametersBuilder.php | 4 +-- .../Paths/Operation/RequestBodyBuilder.php | 6 ++-- src/Concerns/Referencable.php | 30 +++++++++---------- src/Contracts/CallbackFactoryInterface.php | 12 ++++++++ src/Contracts/ExtensionFactoryInterface.php | 15 ++++++++++ src/Contracts/ParametersFactoryInterface.php | 18 +++++++++++ src/Contracts/RequestBodyFactoryInterface.php | 20 +++++++++++++ src/Contracts/ResponseFactoryInterface.php | 15 ++++++++++ src/Contracts/SchemaFactoryInterface.php | 22 ++++++++++++++ .../SecuritySchemeFactoryInterface.php | 12 ++++++++ src/Factories/CallbackFactory.php | 5 ++-- src/Factories/ExtensionFactory.php | 10 ++----- src/Factories/ParametersFactory.php | 9 ++---- src/Factories/RequestBodyFactory.php | 6 ++-- src/Factories/ResponseFactory.php | 6 ++-- src/Factories/SchemaFactory.php | 14 ++------- src/Factories/SecuritySchemeFactory.php | 3 +- tests/PetstoreTest.php | 18 ++++++++++- 31 files changed, 240 insertions(+), 96 deletions(-) create mode 100644 examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php create mode 100644 src/Contracts/CallbackFactoryInterface.php create mode 100644 src/Contracts/ExtensionFactoryInterface.php create mode 100644 src/Contracts/ParametersFactoryInterface.php create mode 100644 src/Contracts/RequestBodyFactoryInterface.php create mode 100644 src/Contracts/ResponseFactoryInterface.php create mode 100644 src/Contracts/SchemaFactoryInterface.php create mode 100644 src/Contracts/SecuritySchemeFactoryInterface.php diff --git a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php new file mode 100644 index 0000000..f608afc --- /dev/null +++ b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php @@ -0,0 +1,27 @@ +description('Pet data') + ->content( + MediaType::json()->schema(PetSchema::ref()) + ); + } + +} \ No newline at end of file diff --git a/examples/petstore/PetController.php b/examples/petstore/PetController.php index 918b8c5..11bbb27 100644 --- a/examples/petstore/PetController.php +++ b/examples/petstore/PetController.php @@ -3,6 +3,7 @@ namespace Examples\Petstore; use Examples\Petstore\OpenApi\Parameters\ListPetsParameters; +use Examples\Petstore\OpenApi\RequestBodies\CreatePetRequestBody; use Examples\Petstore\OpenApi\Responses\ErrorValidationResponse; use Vyuldashev\LaravelOpenApi\Attributes as OpenApi; @@ -18,4 +19,13 @@ class PetController public function index() { } + + /** + * Create pet. + */ + #[OpenApi\Operation('createPet')] + #[OpenApi\RequestBody(CreatePetRequestBody::class)] + public function create() + { + } } diff --git a/src/Attributes/Callback.php b/src/Attributes/Callback.php index 6f1a848..5a1ea83 100644 --- a/src/Attributes/Callback.php +++ b/src/Attributes/Callback.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\CallbackFactory; +use Vyuldashev\LaravelOpenApi\Contracts\CallbackFactoryInterface; #[Attribute] class Callback @@ -13,10 +13,10 @@ class Callback public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Callbacks\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Callbacks\\' . $factory; - if (! is_a($this->factory, CallbackFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of CallbackFactory'); + if (!is_a($this->factory, CallbackFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of CallbackFactoryInterface'); } } } diff --git a/src/Attributes/Extension.php b/src/Attributes/Extension.php index 24fc19f..e678da7 100644 --- a/src/Attributes/Extension.php +++ b/src/Attributes/Extension.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\ExtensionFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ExtensionFactoryInterface; #[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)] class Extension @@ -16,10 +16,10 @@ class Extension public function __construct(string $factory = null, string $key = null, string $value = null) { if ($factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Extensions\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Extensions\\' . $factory; - if (! is_a($this->factory, ExtensionFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of ExtensionFactory'); + if (!is_a($this->factory, ExtensionFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of ExtensionFactoryInterface'); } } diff --git a/src/Attributes/Parameters.php b/src/Attributes/Parameters.php index 3f30d51..0d4df6d 100644 --- a/src/Attributes/Parameters.php +++ b/src/Attributes/Parameters.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ParametersFactoryInterface; #[Attribute(Attribute::TARGET_METHOD)] class Parameters @@ -13,10 +13,10 @@ class Parameters public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Parameters\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Parameters\\' . $factory; - if (! is_a($this->factory, ParametersFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of ParametersFactory'); + if (!is_a($this->factory, ParametersFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of ParametersFactoryInterface'); } } } diff --git a/src/Attributes/RequestBody.php b/src/Attributes/RequestBody.php index a8645fb..ef18fd2 100644 --- a/src/Attributes/RequestBody.php +++ b/src/Attributes/RequestBody.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; #[Attribute(Attribute::TARGET_METHOD)] class RequestBody @@ -13,10 +13,10 @@ class RequestBody public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\RequestBodies\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\RequestBodies\\' . $factory; - if (! is_a($this->factory, RequestBodyFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactory'); + if (!is_a($this->factory, RequestBodyFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactoryInterface'); } } } diff --git a/src/Attributes/Response.php b/src/Attributes/Response.php index a5f82d2..445674b 100644 --- a/src/Attributes/Response.php +++ b/src/Attributes/Response.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ResponseFactoryInterface; #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Response @@ -17,10 +17,10 @@ class Response public function __construct(string $factory, int $statusCode = null, string $description = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Responses\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Responses\\' . $factory; - if (! is_a($this->factory, ResponseFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of ResponseFactory'); + if (!is_a($this->factory, ResponseFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of ResponseFactoryInterface'); } $this->statusCode = $statusCode; diff --git a/src/Builders/Components/CallbacksBuilder.php b/src/Builders/Components/CallbacksBuilder.php index 0e0e79e..9fb63a6 100644 --- a/src/Builders/Components/CallbacksBuilder.php +++ b/src/Builders/Components/CallbacksBuilder.php @@ -2,8 +2,8 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; +use Vyuldashev\LaravelOpenApi\Contracts\CallbackFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\CallbackFactory; use Vyuldashev\LaravelOpenApi\Generator; class CallbacksBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, CallbackFactory::class, true) && + is_a($class, CallbackFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var CallbackFactory $instance */ + /** @var CallbackFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/RequestBodiesBuilder.php b/src/Builders/Components/RequestBodiesBuilder.php index be6fe43..255e904 100644 --- a/src/Builders/Components/RequestBodiesBuilder.php +++ b/src/Builders/Components/RequestBodiesBuilder.php @@ -2,8 +2,8 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; use Vyuldashev\LaravelOpenApi\Generator; class RequestBodiesBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, RequestBodyFactory::class, true) && + is_a($class, RequestBodyFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var RequestBodyFactory $instance */ + /** @var RequestBodyFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/ResponsesBuilder.php b/src/Builders/Components/ResponsesBuilder.php index 86ee458..fa73864 100644 --- a/src/Builders/Components/ResponsesBuilder.php +++ b/src/Builders/Components/ResponsesBuilder.php @@ -2,8 +2,8 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; +use Vyuldashev\LaravelOpenApi\Contracts\ResponseFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory; use Vyuldashev\LaravelOpenApi\Generator; class ResponsesBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, ResponseFactory::class, true) && + is_a($class, ResponseFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var ResponseFactory $instance */ + /** @var ResponseFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/SchemasBuilder.php b/src/Builders/Components/SchemasBuilder.php index 7c1df5f..6081b6b 100644 --- a/src/Builders/Components/SchemasBuilder.php +++ b/src/Builders/Components/SchemasBuilder.php @@ -3,7 +3,7 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory; +use Vyuldashev\LaravelOpenApi\Contracts\SchemaFactoryInterface; use Vyuldashev\LaravelOpenApi\Generator; class SchemasBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, SchemaFactory::class, true) && + is_a($class, SchemaFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var SchemaFactory $instance */ + /** @var SchemaFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/SecuritySchemesBuilder.php b/src/Builders/Components/SecuritySchemesBuilder.php index b7a18fe..7b45147 100644 --- a/src/Builders/Components/SecuritySchemesBuilder.php +++ b/src/Builders/Components/SecuritySchemesBuilder.php @@ -2,7 +2,7 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; -use Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory; +use Vyuldashev\LaravelOpenApi\Contracts\SecuritySchemeFactoryInterface; use Vyuldashev\LaravelOpenApi\Generator; class SecuritySchemesBuilder extends Builder @@ -11,10 +11,10 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array { return $this->getAllClasses($collection) ->filter(static function ($class) { - return is_a($class, SecuritySchemeFactory::class, true); + return is_a($class, SecuritySchemeFactoryInterface::class, true); }) ->map(static function ($class) { - /** @var SecuritySchemeFactory $instance */ + /** @var SecuritySchemeFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/ExtensionsBuilder.php b/src/Builders/ExtensionsBuilder.php index c83dd85..f7063a2 100644 --- a/src/Builders/ExtensionsBuilder.php +++ b/src/Builders/ExtensionsBuilder.php @@ -5,7 +5,7 @@ use GoldSpecDigital\ObjectOrientedOAS\Objects\BaseObject; use Illuminate\Support\Collection; use Vyuldashev\LaravelOpenApi\Attributes\Extension as ExtensionAttribute; -use Vyuldashev\LaravelOpenApi\Factories\ExtensionFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ExtensionFactoryInterface; class ExtensionsBuilder { @@ -15,7 +15,7 @@ public function build(BaseObject $object, Collection $attributes): void ->filter(static fn(object $attribute) => $attribute instanceof ExtensionAttribute) ->each(static function (ExtensionAttribute $attribute) use ($object): void { if ($attribute->factory) { - /** @var ExtensionFactory $factory */ + /** @var ExtensionFactoryInterface $factory */ $factory = app($attribute->factory); $key = $factory->key(); $value = $factory->value(); diff --git a/src/Builders/Paths/Operation/ParametersBuilder.php b/src/Builders/Paths/Operation/ParametersBuilder.php index 78a83ad..366feba 100644 --- a/src/Builders/Paths/Operation/ParametersBuilder.php +++ b/src/Builders/Paths/Operation/ParametersBuilder.php @@ -9,7 +9,7 @@ use phpDocumentor\Reflection\DocBlock\Tags\Param; use ReflectionParameter; use Vyuldashev\LaravelOpenApi\Attributes\Parameters; -use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ParametersFactoryInterface; use Vyuldashev\LaravelOpenApi\RouteInformation; use Vyuldashev\LaravelOpenApi\SchemaHelpers; @@ -60,7 +60,7 @@ protected function buildAttribute(RouteInformation $route): Collection $parameters = $route->actionAttributes->first(static fn($attribute) => $attribute instanceof Parameters, []); if ($parameters) { - /** @var ParametersFactory $parametersFactory */ + /** @var ParametersFactoryInterface $parametersFactory */ $parametersFactory = app($parameters->factory); $parameters = $parametersFactory->build(); diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index 792d06e..9565301 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -4,8 +4,8 @@ use GoldSpecDigital\ObjectOrientedOAS\Objects\RequestBody; use Vyuldashev\LaravelOpenApi\Attributes\RequestBody as RequestBodyAttribute; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; use Vyuldashev\LaravelOpenApi\RouteInformation; class RequestBodyBuilder @@ -16,13 +16,13 @@ public function build(RouteInformation $route): ?RequestBody $requestBody = $route->actionAttributes->first(static fn(object $attribute) => $attribute instanceof RequestBodyAttribute); if ($requestBody) { - /** @var RequestBodyFactory $requestBodyFactory */ + /** @var RequestBodyFactoryInterface $requestBodyFactory */ $requestBodyFactory = app($requestBody->factory); $requestBody = $requestBodyFactory->build(); if ($requestBodyFactory instanceof Reusable) { - return RequestBody::ref('#/components/requestBodies/'.$requestBody->objectId); + return RequestBody::ref('#/components/requestBodies/' . $requestBody->objectId); } } diff --git a/src/Concerns/Referencable.php b/src/Concerns/Referencable.php index fd36525..26b3cae 100644 --- a/src/Concerns/Referencable.php +++ b/src/Concerns/Referencable.php @@ -4,13 +4,13 @@ use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema; use InvalidArgumentException; +use Vyuldashev\LaravelOpenApi\Contracts\CallbackFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\ParametersFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\ResponseFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\CallbackFactory; -use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; -use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory; -use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory; -use Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory; +use Vyuldashev\LaravelOpenApi\Contracts\SchemaFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\SecuritySchemeFactoryInterface; trait Referencable { @@ -18,26 +18,26 @@ public static function ref(?string $objectId = null): Schema { $instance = app(static::class); - if (! $instance instanceof Reusable) { - throw new InvalidArgumentException('"'.static::class.'" must implement "'.Reusable::class.'" in order to be referencable.'); + if (!$instance instanceof Reusable) { + throw new InvalidArgumentException('"' . static::class . '" must implement "' . Reusable::class . '" in order to be referencable.'); } $baseRef = null; - if ($instance instanceof CallbackFactory) { + if ($instance instanceof CallbackFactoryInterface) { $baseRef = '#/components/callbacks/'; - } elseif ($instance instanceof ParametersFactory) { + } elseif ($instance instanceof ParametersFactoryInterface) { $baseRef = '#/components/parameters/'; - } elseif ($instance instanceof RequestBodyFactory) { + } elseif ($instance instanceof RequestBodyFactoryInterface) { $baseRef = '#/components/requestBodies/'; - } elseif ($instance instanceof ResponseFactory) { + } elseif ($instance instanceof ResponseFactoryInterface) { $baseRef = '#/components/responses/'; - } elseif ($instance instanceof SchemaFactory) { + } elseif ($instance instanceof SchemaFactoryInterface) { $baseRef = '#/components/schemas/'; - } elseif ($instance instanceof SecuritySchemeFactory) { + } elseif ($instance instanceof SecuritySchemeFactoryInterface) { $baseRef = '#/components/securitySchemes/'; } - return Schema::ref($baseRef.$instance->build()->objectId, $objectId); + return Schema::ref($baseRef . $instance->build()->objectId, $objectId); } } diff --git a/src/Contracts/CallbackFactoryInterface.php b/src/Contracts/CallbackFactoryInterface.php new file mode 100644 index 0000000..0a5233c --- /dev/null +++ b/src/Contracts/CallbackFactoryInterface.php @@ -0,0 +1,12 @@ +set('openapi.locations.schemas', [ - __DIR__.'/../examples/petstore/OpenApi/Schemas', + __DIR__ . '/../examples/petstore/OpenApi/Schemas', ]); } @@ -80,5 +81,20 @@ public function testGenerate(): void ], ], ], $spec['components']['schemas']['Pet']); + + self::assertEquals([ + 'summary' => 'Create pet.', + 'operationId' => 'createPet', + 'requestBody' => [ + "description" => "Pet data", + "content" => [ + "application/json" => [ + "schema" => [ + '$ref' => "#/components/schemas/Pet", + ] + ], + ], + ], + ], $spec['paths']['/pet']['post']); } } From 1ed6b5e04b4f3c1ee5afa11d3165ad712a2f6f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 2 Mar 2021 08:42:09 +0100 Subject: [PATCH 02/20] Add custom data to Parameters, RequestBody and Response --- examples/petstore/OpenApi/Parameters/ListPetsParameters.php | 2 +- .../petstore/OpenApi/RequestBodies/CreatePetRequestBody.php | 2 +- .../petstore/OpenApi/Responses/ErrorValidationResponse.php | 2 +- examples/petstore/PetController.php | 6 +++--- src/Attributes/Parameters.php | 4 +++- src/Attributes/RequestBody.php | 4 +++- src/Attributes/Response.php | 5 ++++- src/Builders/Paths/Operation/ParametersBuilder.php | 3 ++- src/Builders/Paths/Operation/RequestBodyBuilder.php | 3 ++- src/Builders/Paths/Operation/ResponsesBuilder.php | 4 +++- tests/PetstoreTest.php | 4 ++-- 11 files changed, 25 insertions(+), 14 deletions(-) diff --git a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php index ff220f2..b003382 100644 --- a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php +++ b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php @@ -17,7 +17,7 @@ public function build(): array Parameter::query() ->name('limit') - ->description('How many items to return at one time (max 100)') + ->description('How many items to return at one time (max 100) ' . $this->data) ->required(false) ->schema( Schema::integer()->format(Schema::FORMAT_INT32) diff --git a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php index f608afc..e31f12f 100644 --- a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php +++ b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php @@ -18,7 +18,7 @@ class CreatePetRequestBody implements RequestBodyFactoryInterface public function build(): RequestBody { return RequestBody::create('UserCreate') - ->description('Pet data') + ->description($this->data['custom']) ->content( MediaType::json()->schema(PetSchema::ref()) ); diff --git a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php index 2b28287..f8b7d0a 100644 --- a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php +++ b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php @@ -13,7 +13,7 @@ class ErrorValidationResponse extends ResponseFactory implements Reusable public function build(): Response { $response = Schema::object()->properties( - Schema::string('message')->example('The given data was invalid.'), + Schema::string('message')->example('The given data was invalid. ' . $this->data), Schema::object('errors') ->additionalProperties( Schema::array()->items(Schema::string()) diff --git a/examples/petstore/PetController.php b/examples/petstore/PetController.php index 11bbb27..0a07d43 100644 --- a/examples/petstore/PetController.php +++ b/examples/petstore/PetController.php @@ -14,8 +14,8 @@ class PetController * List all pets. */ #[OpenApi\Operation('listPets')] - #[OpenApi\Parameters(ListPetsParameters::class)] - #[OpenApi\Response(ErrorValidationResponse::class, 422)] + #[OpenApi\Parameters(ListPetsParameters::class, "Parameters custom data")] + #[OpenApi\Response(ErrorValidationResponse::class, 422, "", "Response custom data")] public function index() { } @@ -24,7 +24,7 @@ public function index() * Create pet. */ #[OpenApi\Operation('createPet')] - #[OpenApi\RequestBody(CreatePetRequestBody::class)] + #[OpenApi\RequestBody(CreatePetRequestBody::class, ["custom" => "My custom data"])] public function create() { } diff --git a/src/Attributes/Parameters.php b/src/Attributes/Parameters.php index 0d4df6d..268318e 100644 --- a/src/Attributes/Parameters.php +++ b/src/Attributes/Parameters.php @@ -10,10 +10,12 @@ class Parameters { public string $factory; + public $data; - public function __construct(string $factory) + public function __construct(string $factory, $data = null) { $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Parameters\\' . $factory; + $this->data = $data; if (!is_a($this->factory, ParametersFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ParametersFactoryInterface'); diff --git a/src/Attributes/RequestBody.php b/src/Attributes/RequestBody.php index ef18fd2..59cb148 100644 --- a/src/Attributes/RequestBody.php +++ b/src/Attributes/RequestBody.php @@ -10,10 +10,12 @@ class RequestBody { public string $factory; + public $data; - public function __construct(string $factory) + public function __construct(string $factory, $data = null) { $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\RequestBodies\\' . $factory; + $this->data = $data; if (!is_a($this->factory, RequestBodyFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactoryInterface'); diff --git a/src/Attributes/Response.php b/src/Attributes/Response.php index 445674b..34aa664 100644 --- a/src/Attributes/Response.php +++ b/src/Attributes/Response.php @@ -15,9 +15,12 @@ class Response public ?string $description; - public function __construct(string $factory, int $statusCode = null, string $description = null) + public $data; + + public function __construct(string $factory, int $statusCode = null, string $description = null, $data = null) { $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Responses\\' . $factory; + $this->data = $data; if (!is_a($this->factory, ResponseFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ResponseFactoryInterface'); diff --git a/src/Builders/Paths/Operation/ParametersBuilder.php b/src/Builders/Paths/Operation/ParametersBuilder.php index 366feba..e96bdb7 100644 --- a/src/Builders/Paths/Operation/ParametersBuilder.php +++ b/src/Builders/Paths/Operation/ParametersBuilder.php @@ -62,7 +62,8 @@ protected function buildAttribute(RouteInformation $route): Collection if ($parameters) { /** @var ParametersFactoryInterface $parametersFactory */ $parametersFactory = app($parameters->factory); - + // little bit magic, add custom data into factory + $parametersFactory->data = $parameters->data; $parameters = $parametersFactory->build(); } diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index 9565301..2fa182b 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -18,7 +18,8 @@ public function build(RouteInformation $route): ?RequestBody if ($requestBody) { /** @var RequestBodyFactoryInterface $requestBodyFactory */ $requestBodyFactory = app($requestBody->factory); - + // little bit magic, add custom data into factory + $requestBodyFactory->data = $requestBody->data; $requestBody = $requestBodyFactory->build(); if ($requestBodyFactory instanceof Reusable) { diff --git a/src/Builders/Paths/Operation/ResponsesBuilder.php b/src/Builders/Paths/Operation/ResponsesBuilder.php index 3a91321..74fe97b 100644 --- a/src/Builders/Paths/Operation/ResponsesBuilder.php +++ b/src/Builders/Paths/Operation/ResponsesBuilder.php @@ -15,10 +15,12 @@ public function build(RouteInformation $route): array ->filter(static fn(object $attribute) => $attribute instanceof ResponseAttribute) ->map(static function (ResponseAttribute $attribute) { $factory = app($attribute->factory); + // little bit magic, add custom data into factory + $factory->data = $attribute->data; $response = $factory->build(); if ($factory instanceof Reusable) { - return Response::ref('#/components/responses/'.$response->objectId) + return Response::ref('#/components/responses/' . $response->objectId) ->statusCode($attribute->statusCode) ->description($attribute->description); } diff --git a/tests/PetstoreTest.php b/tests/PetstoreTest.php index ab82843..0255650 100644 --- a/tests/PetstoreTest.php +++ b/tests/PetstoreTest.php @@ -43,7 +43,7 @@ public function testGenerate(): void [ 'name' => 'limit', 'in' => 'query', - 'description' => 'How many items to return at one time (max 100)', + 'description' => 'How many items to return at one time (max 100) Parameters custom data', 'required' => false, 'schema' => [ 'format' => 'int32', @@ -86,7 +86,7 @@ public function testGenerate(): void 'summary' => 'Create pet.', 'operationId' => 'createPet', 'requestBody' => [ - "description" => "Pet data", + "description" => "My custom data", "content" => [ "application/json" => [ "schema" => [ From cc18721b60eba41b7f1ab758dbf48ab5124cd8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 2 Mar 2021 08:43:34 +0100 Subject: [PATCH 03/20] Add Makefile with docker --- Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5087f9a --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +#!make + +.PHONY: tests + +COMPOSE_IMAGE = composer:2 +PHP_IMAGE=php:8 + +composer: + docker pull $(DOCKER_COMPOSE) + docker run --rm --interactive --tty --user $(id -u):$(id -g) -w /app --volume `pwd`:/app $(COMPOSE_IMAGE) composer $(P) + +composer_install: + make composer P="install" + +phpunit: + docker pull $(PHP_IMAGE) + docker run --rm -it --user $(id -u):$(id -g) -w /app --volume `pwd`:/app $(PHP_IMAGE) ./vendor/bin/phpunit $(P) + +# run all php unit tests +tests: + make phpunit P=tests \ No newline at end of file From 5e3e1c8954edd00e43788c05aec08c7f00332d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Wed, 3 Mar 2021 11:29:23 +0100 Subject: [PATCH 04/20] package name update --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 57c7b78..1e0ec2e 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "vyuldashev/laravel-openapi", + "name": "ogsoft/laravel-openapi", "description": "Generate OpenAPI Specification for Laravel Applications", "keywords": [ "laravel", From f140a8e5b82c6f1b3cf7391197c3eacfc5b01e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 12 Oct 2021 09:28:46 +0200 Subject: [PATCH 05/20] format fix --- .../OpenApi/Parameters/ListPetsParameters.php | 2 +- .../OpenApi/RequestBodies/CreatePetRequestBody.php | 6 +----- .../OpenApi/Responses/ErrorValidationResponse.php | 2 +- examples/petstore/PetController.php | 6 +++--- src/Attributes/Callback.php | 4 ++-- src/Attributes/Extension.php | 4 ++-- src/Attributes/Parameters.php | 4 ++-- src/Attributes/RequestBody.php | 4 ++-- src/Attributes/Response.php | 4 ++-- src/Builders/ExtensionsBuilder.php | 2 +- src/Builders/Paths/Operation/ParametersBuilder.php | 6 +++--- .../Paths/Operation/RequestBodyBuilder.php | 4 ++-- src/Builders/Paths/Operation/ResponsesBuilder.php | 4 ++-- src/Concerns/Referencable.php | 6 +++--- src/Contracts/CallbackFactoryInterface.php | 4 +--- src/Contracts/ExtensionFactoryInterface.php | 4 +--- src/Contracts/ParametersFactoryInterface.php | 4 +--- src/Contracts/RequestBodyFactoryInterface.php | 7 ++----- src/Contracts/ResponseFactoryInterface.php | 4 +--- src/Contracts/SchemaFactoryInterface.php | 4 +--- src/Contracts/SecuritySchemeFactoryInterface.php | 4 +--- tests/PetstoreTest.php | 14 +++++++------- 22 files changed, 42 insertions(+), 61 deletions(-) diff --git a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php index b003382..c3be644 100644 --- a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php +++ b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php @@ -17,7 +17,7 @@ public function build(): array Parameter::query() ->name('limit') - ->description('How many items to return at one time (max 100) ' . $this->data) + ->description('How many items to return at one time (max 100) '.$this->data) ->required(false) ->schema( Schema::integer()->format(Schema::FORMAT_INT32) diff --git a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php index e31f12f..17799f6 100644 --- a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php +++ b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php @@ -1,9 +1,7 @@ schema(PetSchema::ref()) ); } - -} \ No newline at end of file +} diff --git a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php index f8b7d0a..9604094 100644 --- a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php +++ b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php @@ -13,7 +13,7 @@ class ErrorValidationResponse extends ResponseFactory implements Reusable public function build(): Response { $response = Schema::object()->properties( - Schema::string('message')->example('The given data was invalid. ' . $this->data), + Schema::string('message')->example('The given data was invalid. '.$this->data), Schema::object('errors') ->additionalProperties( Schema::array()->items(Schema::string()) diff --git a/examples/petstore/PetController.php b/examples/petstore/PetController.php index 0a07d43..7ce92ba 100644 --- a/examples/petstore/PetController.php +++ b/examples/petstore/PetController.php @@ -14,8 +14,8 @@ class PetController * List all pets. */ #[OpenApi\Operation('listPets')] - #[OpenApi\Parameters(ListPetsParameters::class, "Parameters custom data")] - #[OpenApi\Response(ErrorValidationResponse::class, 422, "", "Response custom data")] + #[OpenApi\Parameters(ListPetsParameters::class, 'Parameters custom data')] + #[OpenApi\Response(ErrorValidationResponse::class, 422, '', 'Response custom data')] public function index() { } @@ -24,7 +24,7 @@ public function index() * Create pet. */ #[OpenApi\Operation('createPet')] - #[OpenApi\RequestBody(CreatePetRequestBody::class, ["custom" => "My custom data"])] + #[OpenApi\RequestBody(CreatePetRequestBody::class, ['custom' => 'My custom data'])] public function create() { } diff --git a/src/Attributes/Callback.php b/src/Attributes/Callback.php index 5a1ea83..c3149da 100644 --- a/src/Attributes/Callback.php +++ b/src/Attributes/Callback.php @@ -13,9 +13,9 @@ class Callback public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Callbacks\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Callbacks\\'.$factory; - if (!is_a($this->factory, CallbackFactoryInterface::class, true)) { + if (! is_a($this->factory, CallbackFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of CallbackFactoryInterface'); } } diff --git a/src/Attributes/Extension.php b/src/Attributes/Extension.php index e678da7..2de21db 100644 --- a/src/Attributes/Extension.php +++ b/src/Attributes/Extension.php @@ -16,9 +16,9 @@ class Extension public function __construct(string $factory = null, string $key = null, string $value = null) { if ($factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Extensions\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Extensions\\'.$factory; - if (!is_a($this->factory, ExtensionFactoryInterface::class, true)) { + if (! is_a($this->factory, ExtensionFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ExtensionFactoryInterface'); } } diff --git a/src/Attributes/Parameters.php b/src/Attributes/Parameters.php index 268318e..776a980 100644 --- a/src/Attributes/Parameters.php +++ b/src/Attributes/Parameters.php @@ -14,10 +14,10 @@ class Parameters public function __construct(string $factory, $data = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Parameters\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Parameters\\'.$factory; $this->data = $data; - if (!is_a($this->factory, ParametersFactoryInterface::class, true)) { + if (! is_a($this->factory, ParametersFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ParametersFactoryInterface'); } } diff --git a/src/Attributes/RequestBody.php b/src/Attributes/RequestBody.php index 59cb148..cb01f8f 100644 --- a/src/Attributes/RequestBody.php +++ b/src/Attributes/RequestBody.php @@ -14,10 +14,10 @@ class RequestBody public function __construct(string $factory, $data = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\RequestBodies\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\RequestBodies\\'.$factory; $this->data = $data; - if (!is_a($this->factory, RequestBodyFactoryInterface::class, true)) { + if (! is_a($this->factory, RequestBodyFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactoryInterface'); } } diff --git a/src/Attributes/Response.php b/src/Attributes/Response.php index 34aa664..b5de7ad 100644 --- a/src/Attributes/Response.php +++ b/src/Attributes/Response.php @@ -19,10 +19,10 @@ class Response public function __construct(string $factory, int $statusCode = null, string $description = null, $data = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Responses\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Responses\\'.$factory; $this->data = $data; - if (!is_a($this->factory, ResponseFactoryInterface::class, true)) { + if (! is_a($this->factory, ResponseFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ResponseFactoryInterface'); } diff --git a/src/Builders/ExtensionsBuilder.php b/src/Builders/ExtensionsBuilder.php index f7063a2..8329ce5 100644 --- a/src/Builders/ExtensionsBuilder.php +++ b/src/Builders/ExtensionsBuilder.php @@ -12,7 +12,7 @@ class ExtensionsBuilder public function build(BaseObject $object, Collection $attributes): void { $attributes - ->filter(static fn(object $attribute) => $attribute instanceof ExtensionAttribute) + ->filter(static fn (object $attribute) => $attribute instanceof ExtensionAttribute) ->each(static function (ExtensionAttribute $attribute) use ($object): void { if ($attribute->factory) { /** @var ExtensionFactoryInterface $factory */ diff --git a/src/Builders/Paths/Operation/ParametersBuilder.php b/src/Builders/Paths/Operation/ParametersBuilder.php index e96bdb7..f652877 100644 --- a/src/Builders/Paths/Operation/ParametersBuilder.php +++ b/src/Builders/Paths/Operation/ParametersBuilder.php @@ -31,7 +31,7 @@ protected function buildPath(RouteInformation $route): Collection /** @var ReflectionParameter|null $reflectionParameter */ $reflectionParameter = collect($route->actionParameters) - ->first(static fn(ReflectionParameter $reflectionParameter) => $reflectionParameter->name === $parameter['name']); + ->first(static fn (ReflectionParameter $reflectionParameter) => $reflectionParameter->name === $parameter['name']); if ($reflectionParameter) { // The reflected param has no type, so ignore (should be defined in a ParametersFactory instead) @@ -44,7 +44,7 @@ protected function buildPath(RouteInformation $route): Collection /** @var Param $description */ $description = collect($route->actionDocBlock->getTagsByName('param')) - ->first(static fn(Param $param) => Str::snake($param->getVariableName()) === Str::snake($parameter['name'])); + ->first(static fn (Param $param) => Str::snake($param->getVariableName()) === Str::snake($parameter['name'])); return Parameter::path()->name($parameter['name']) ->required() @@ -57,7 +57,7 @@ protected function buildPath(RouteInformation $route): Collection protected function buildAttribute(RouteInformation $route): Collection { /** @var Parameters|null $parameters */ - $parameters = $route->actionAttributes->first(static fn($attribute) => $attribute instanceof Parameters, []); + $parameters = $route->actionAttributes->first(static fn ($attribute) => $attribute instanceof Parameters, []); if ($parameters) { /** @var ParametersFactoryInterface $parametersFactory */ diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index 2fa182b..1b4a5ff 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -13,7 +13,7 @@ class RequestBodyBuilder public function build(RouteInformation $route): ?RequestBody { /** @var RequestBodyAttribute|null $requestBody */ - $requestBody = $route->actionAttributes->first(static fn(object $attribute) => $attribute instanceof RequestBodyAttribute); + $requestBody = $route->actionAttributes->first(static fn (object $attribute) => $attribute instanceof RequestBodyAttribute); if ($requestBody) { /** @var RequestBodyFactoryInterface $requestBodyFactory */ @@ -23,7 +23,7 @@ public function build(RouteInformation $route): ?RequestBody $requestBody = $requestBodyFactory->build(); if ($requestBodyFactory instanceof Reusable) { - return RequestBody::ref('#/components/requestBodies/' . $requestBody->objectId); + return RequestBody::ref('#/components/requestBodies/'.$requestBody->objectId); } } diff --git a/src/Builders/Paths/Operation/ResponsesBuilder.php b/src/Builders/Paths/Operation/ResponsesBuilder.php index 74fe97b..b6aeb11 100644 --- a/src/Builders/Paths/Operation/ResponsesBuilder.php +++ b/src/Builders/Paths/Operation/ResponsesBuilder.php @@ -12,7 +12,7 @@ class ResponsesBuilder public function build(RouteInformation $route): array { return $route->actionAttributes - ->filter(static fn(object $attribute) => $attribute instanceof ResponseAttribute) + ->filter(static fn (object $attribute) => $attribute instanceof ResponseAttribute) ->map(static function (ResponseAttribute $attribute) { $factory = app($attribute->factory); // little bit magic, add custom data into factory @@ -20,7 +20,7 @@ public function build(RouteInformation $route): array $response = $factory->build(); if ($factory instanceof Reusable) { - return Response::ref('#/components/responses/' . $response->objectId) + return Response::ref('#/components/responses/'.$response->objectId) ->statusCode($attribute->statusCode) ->description($attribute->description); } diff --git a/src/Concerns/Referencable.php b/src/Concerns/Referencable.php index 26b3cae..fdf4209 100644 --- a/src/Concerns/Referencable.php +++ b/src/Concerns/Referencable.php @@ -18,8 +18,8 @@ public static function ref(?string $objectId = null): Schema { $instance = app(static::class); - if (!$instance instanceof Reusable) { - throw new InvalidArgumentException('"' . static::class . '" must implement "' . Reusable::class . '" in order to be referencable.'); + if (! $instance instanceof Reusable) { + throw new InvalidArgumentException('"'.static::class.'" must implement "'.Reusable::class.'" in order to be referencable.'); } $baseRef = null; @@ -38,6 +38,6 @@ public static function ref(?string $objectId = null): Schema $baseRef = '#/components/securitySchemes/'; } - return Schema::ref($baseRef . $instance->build()->objectId, $objectId); + return Schema::ref($baseRef.$instance->build()->objectId, $objectId); } } diff --git a/src/Contracts/CallbackFactoryInterface.php b/src/Contracts/CallbackFactoryInterface.php index 0a5233c..df14204 100644 --- a/src/Contracts/CallbackFactoryInterface.php +++ b/src/Contracts/CallbackFactoryInterface.php @@ -1,12 +1,10 @@ set('openapi.locations.schemas', [ - __DIR__ . '/../examples/petstore/OpenApi/Schemas', + __DIR__.'/../examples/petstore/OpenApi/Schemas', ]); } @@ -86,12 +86,12 @@ public function testGenerate(): void 'summary' => 'Create pet.', 'operationId' => 'createPet', 'requestBody' => [ - "description" => "My custom data", - "content" => [ - "application/json" => [ - "schema" => [ - '$ref' => "#/components/schemas/Pet", - ] + 'description' => 'My custom data', + 'content' => [ + 'application/json' => [ + 'schema' => [ + '$ref' => '#/components/schemas/Pet', + ], ], ], ], From 63df64e556b3d864c81015054f21730fa88f6e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 12 Oct 2021 09:29:34 +0200 Subject: [PATCH 06/20] format fix --- src/Contracts/RequestBodyFactoryInterface.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Contracts/RequestBodyFactoryInterface.php b/src/Contracts/RequestBodyFactoryInterface.php index cacdf01..2f4cb0b 100644 --- a/src/Contracts/RequestBodyFactoryInterface.php +++ b/src/Contracts/RequestBodyFactoryInterface.php @@ -7,6 +7,7 @@ /** * Interface RequestBodyFactoryInterface. + * * @var $data */ interface RequestBodyFactoryInterface From 8bf73ad80df147656e8a104e7dce7f2f718d5acc Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 17:40:31 +0200 Subject: [PATCH 07/20] Laravel 9.x Compatibility --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 1e0ec2e..2993734 100644 --- a/composer.json +++ b/composer.json @@ -23,11 +23,11 @@ "ext-json": "*", "doctrine/dbal": "^2.6|^3.0", "goldspecdigital/oooas": "^2.7.1", - "laravel/framework": "5.8.*|^6.0|^7.0|^8.0", + "laravel/framework": "5.8.*|^6.0|^7.0|^8.0|^9.0", "phpdocumentor/reflection-docblock": "^5.0" }, "require-dev": { - "orchestra/testbench": "^5.3|^6.0", + "orchestra/testbench": "^5.3|^6.0|^7.0", "phpunit/phpunit": "^9.4" }, "autoload": { From 91eae28d43bf711ae4558ba0a4e55ef68545ef90 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:18:28 +0200 Subject: [PATCH 08/20] Add security to Operation Attribute --- src/Attributes/Operation.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Attributes/Operation.php b/src/Attributes/Operation.php index 183d0dd..27661cf 100644 --- a/src/Attributes/Operation.php +++ b/src/Attributes/Operation.php @@ -9,15 +9,19 @@ class Operation { public ?string $id; + /** @var array */ + public array $security; + /** @var array */ public array $tags; public ?string $method; - public function __construct(string $id = null, array $tags = [], string $method = null) + public function __construct(string $id = null, array $tags = [], array $security = [], string $method = null) { $this->id = $id; $this->tags = $tags; + $this->security = $security; $this->method = $method; } } From 250ae9f6ef7dcf8f916fcf8801047d592d69dc08 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:31:55 +0200 Subject: [PATCH 09/20] Update Operation.php --- src/Attributes/Operation.php | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Attributes/Operation.php b/src/Attributes/Operation.php index 27661cf..b304db3 100644 --- a/src/Attributes/Operation.php +++ b/src/Attributes/Operation.php @@ -3,25 +3,42 @@ namespace Vyuldashev\LaravelOpenApi\Attributes; use Attribute; +use InvalidArgumentException; +use Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory; #[Attribute(Attribute::TARGET_METHOD)] class Operation { public ?string $id; - /** @var array */ - public array $security; - /** @var array */ public array $tags; + public ?string $security; + public ?string $method; - public function __construct(string $id = null, array $tags = [], array $security = [], string $method = null) + /** + * @param string|null $id + * @param array $tags + * @param \Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory|string|null $security + * @param string|null $method + * @throws InvalidArgumentException + */ + public function __construct(string $id = null, array $tags = [], string $security = null, string $method = null) { $this->id = $id; $this->tags = $tags; - $this->security = $security; $this->method = $method; + + if ($security) { + $this->security = class_exists($security) ? $security : app()->getNamespace() . 'OpenApi\\SecuritySchemes\\' . $security . 'SecurityScheme'; + + if (!is_a($this->security, SecuritySchemeFactory::class, true)) { + throw new InvalidArgumentException( + sprintf('Security class is either not declared or is not an instance of [%s]', SecuritySchemeFactory::class) + ); + } + } } } From 4856d12ea52202fddd20a16d828945866cef5009 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:32:40 +0200 Subject: [PATCH 10/20] Create SecurityBuilder.php --- .../Paths/Operation/SecurityBuilder.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/Builders/Paths/Operation/SecurityBuilder.php diff --git a/src/Builders/Paths/Operation/SecurityBuilder.php b/src/Builders/Paths/Operation/SecurityBuilder.php new file mode 100644 index 0000000..a7fb54a --- /dev/null +++ b/src/Builders/Paths/Operation/SecurityBuilder.php @@ -0,0 +1,25 @@ +actionAttributes + ->filter(static fn (object $attribute) => $attribute instanceof OperationAttribute) + ->filter(static fn (OperationAttribute $attribute) => isset($attribute->security)) + ->map(static function (OperationAttribute $attribute) { + $security = app($attribute->security); + $scheme = $security->build(); + + return SecurityRequirement::create()->securityScheme($scheme); + }) + ->values() + ->toArray(); + } +} From 524c89ec743c389b41a940f92b34a40c651b2315 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:34:06 +0200 Subject: [PATCH 11/20] Update OperationsBuilder.php --- src/Builders/Paths/OperationsBuilder.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Builders/Paths/OperationsBuilder.php b/src/Builders/Paths/OperationsBuilder.php index 3279cb0..c8ca455 100644 --- a/src/Builders/Paths/OperationsBuilder.php +++ b/src/Builders/Paths/OperationsBuilder.php @@ -4,14 +4,18 @@ use GoldSpecDigital\ObjectOrientedOAS\Exceptions\InvalidArgumentException; use GoldSpecDigital\ObjectOrientedOAS\Objects\Operation; +use GoldSpecDigital\ObjectOrientedOAS\Objects\SecurityRequirement; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Vyuldashev\LaravelOpenApi\Attributes\Operation as OperationAttribute; +use Vyuldashev\LaravelOpenApi\Builders\Components\SecuritySchemesBuilder; use Vyuldashev\LaravelOpenApi\Builders\ExtensionsBuilder; use Vyuldashev\LaravelOpenApi\Builders\Paths\Operation\CallbacksBuilder; use Vyuldashev\LaravelOpenApi\Builders\Paths\Operation\ParametersBuilder; use Vyuldashev\LaravelOpenApi\Builders\Paths\Operation\RequestBodyBuilder; use Vyuldashev\LaravelOpenApi\Builders\Paths\Operation\ResponsesBuilder; +use Vyuldashev\LaravelOpenApi\Builders\Paths\Operation\SecurityBuilder; +use Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory; use Vyuldashev\LaravelOpenApi\RouteInformation; class OperationsBuilder @@ -21,19 +25,22 @@ class OperationsBuilder protected RequestBodyBuilder $requestBodyBuilder; protected ResponsesBuilder $responsesBuilder; protected ExtensionsBuilder $extensionsBuilder; + protected SecurityBuilder $securityBuilder; public function __construct( CallbacksBuilder $callbacksBuilder, ParametersBuilder $parametersBuilder, RequestBodyBuilder $requestBodyBuilder, ResponsesBuilder $responsesBuilder, - ExtensionsBuilder $extensionsBuilder + ExtensionsBuilder $extensionsBuilder, + SecurityBuilder $securityBuilder ) { $this->callbacksBuilder = $callbacksBuilder; $this->parametersBuilder = $parametersBuilder; $this->requestBodyBuilder = $requestBodyBuilder; $this->responsesBuilder = $responsesBuilder; $this->extensionsBuilder = $extensionsBuilder; + $this->securityBuilder = $securityBuilder; } /** @@ -41,7 +48,7 @@ public function __construct( * @return array * @throws InvalidArgumentException */ - public function build(array|Collection $routes): array + public function build(array | Collection $routes): array { $operations = []; @@ -49,7 +56,7 @@ public function build(array|Collection $routes): array foreach ($routes as $route) { /** @var OperationAttribute|null $operationAttribute */ $operationAttribute = $route->actionAttributes - ->first(static fn(object $attribute) => $attribute instanceof OperationAttribute); + ->first(static fn (object $attribute) => $attribute instanceof OperationAttribute); $operationId = optional($operationAttribute)->id; $tags = $operationAttribute->tags ?? []; @@ -58,6 +65,7 @@ public function build(array|Collection $routes): array $requestBody = $this->requestBodyBuilder->build($route); $responses = $this->responsesBuilder->build($route); $callbacks = $this->callbacksBuilder->build($route); + $security = $this->securityBuilder->build($route); $operation = Operation::create() ->action(Str::lower($operationAttribute->method) ?: $route->method) @@ -68,7 +76,8 @@ public function build(array|Collection $routes): array ->parameters(...$parameters) ->requestBody($requestBody) ->responses(...$responses) - ->callbacks(...$callbacks); + ->callbacks(...$callbacks) + ->security(...$security); $this->extensionsBuilder->build($operation, $route->actionAttributes); From 37f3d70fe10d5ac4c9e230db26a7cf6c08ba3f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 2 Mar 2021 08:17:31 +0100 Subject: [PATCH 12/20] Add factory interfaces --- .../RequestBodies/CreatePetRequestBody.php | 27 +++++++++++++++++ examples/petstore/PetController.php | 10 +++++++ src/Attributes/Callback.php | 8 ++--- src/Attributes/Extension.php | 8 ++--- src/Attributes/Parameters.php | 8 ++--- src/Attributes/RequestBody.php | 8 ++--- src/Attributes/Response.php | 8 ++--- src/Builders/Components/CallbacksBuilder.php | 6 ++-- .../Components/RequestBodiesBuilder.php | 6 ++-- src/Builders/Components/ResponsesBuilder.php | 6 ++-- src/Builders/Components/SchemasBuilder.php | 6 ++-- .../Components/SecuritySchemesBuilder.php | 6 ++-- src/Builders/ExtensionsBuilder.php | 4 +-- .../Paths/Operation/ParametersBuilder.php | 4 +-- .../Paths/Operation/RequestBodyBuilder.php | 6 ++-- src/Concerns/Referencable.php | 30 +++++++++---------- src/Contracts/CallbackFactoryInterface.php | 12 ++++++++ src/Contracts/ExtensionFactoryInterface.php | 15 ++++++++++ src/Contracts/ParametersFactoryInterface.php | 18 +++++++++++ src/Contracts/RequestBodyFactoryInterface.php | 20 +++++++++++++ src/Contracts/ResponseFactoryInterface.php | 15 ++++++++++ src/Contracts/SchemaFactoryInterface.php | 22 ++++++++++++++ .../SecuritySchemeFactoryInterface.php | 12 ++++++++ src/Factories/CallbackFactory.php | 5 ++-- src/Factories/ExtensionFactory.php | 10 ++----- src/Factories/ParametersFactory.php | 9 ++---- src/Factories/RequestBodyFactory.php | 6 ++-- src/Factories/ResponseFactory.php | 6 ++-- src/Factories/SchemaFactory.php | 14 ++------- src/Factories/SecuritySchemeFactory.php | 3 +- tests/PetstoreTest.php | 18 ++++++++++- 31 files changed, 240 insertions(+), 96 deletions(-) create mode 100644 examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php create mode 100644 src/Contracts/CallbackFactoryInterface.php create mode 100644 src/Contracts/ExtensionFactoryInterface.php create mode 100644 src/Contracts/ParametersFactoryInterface.php create mode 100644 src/Contracts/RequestBodyFactoryInterface.php create mode 100644 src/Contracts/ResponseFactoryInterface.php create mode 100644 src/Contracts/SchemaFactoryInterface.php create mode 100644 src/Contracts/SecuritySchemeFactoryInterface.php diff --git a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php new file mode 100644 index 0000000..f608afc --- /dev/null +++ b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php @@ -0,0 +1,27 @@ +description('Pet data') + ->content( + MediaType::json()->schema(PetSchema::ref()) + ); + } + +} \ No newline at end of file diff --git a/examples/petstore/PetController.php b/examples/petstore/PetController.php index 918b8c5..11bbb27 100644 --- a/examples/petstore/PetController.php +++ b/examples/petstore/PetController.php @@ -3,6 +3,7 @@ namespace Examples\Petstore; use Examples\Petstore\OpenApi\Parameters\ListPetsParameters; +use Examples\Petstore\OpenApi\RequestBodies\CreatePetRequestBody; use Examples\Petstore\OpenApi\Responses\ErrorValidationResponse; use Vyuldashev\LaravelOpenApi\Attributes as OpenApi; @@ -18,4 +19,13 @@ class PetController public function index() { } + + /** + * Create pet. + */ + #[OpenApi\Operation('createPet')] + #[OpenApi\RequestBody(CreatePetRequestBody::class)] + public function create() + { + } } diff --git a/src/Attributes/Callback.php b/src/Attributes/Callback.php index 6f1a848..5a1ea83 100644 --- a/src/Attributes/Callback.php +++ b/src/Attributes/Callback.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\CallbackFactory; +use Vyuldashev\LaravelOpenApi\Contracts\CallbackFactoryInterface; #[Attribute] class Callback @@ -13,10 +13,10 @@ class Callback public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Callbacks\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Callbacks\\' . $factory; - if (! is_a($this->factory, CallbackFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of CallbackFactory'); + if (!is_a($this->factory, CallbackFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of CallbackFactoryInterface'); } } } diff --git a/src/Attributes/Extension.php b/src/Attributes/Extension.php index 24fc19f..e678da7 100644 --- a/src/Attributes/Extension.php +++ b/src/Attributes/Extension.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\ExtensionFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ExtensionFactoryInterface; #[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)] class Extension @@ -16,10 +16,10 @@ class Extension public function __construct(string $factory = null, string $key = null, string $value = null) { if ($factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Extensions\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Extensions\\' . $factory; - if (! is_a($this->factory, ExtensionFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of ExtensionFactory'); + if (!is_a($this->factory, ExtensionFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of ExtensionFactoryInterface'); } } diff --git a/src/Attributes/Parameters.php b/src/Attributes/Parameters.php index 3f30d51..0d4df6d 100644 --- a/src/Attributes/Parameters.php +++ b/src/Attributes/Parameters.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ParametersFactoryInterface; #[Attribute(Attribute::TARGET_METHOD)] class Parameters @@ -13,10 +13,10 @@ class Parameters public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Parameters\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Parameters\\' . $factory; - if (! is_a($this->factory, ParametersFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of ParametersFactory'); + if (!is_a($this->factory, ParametersFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of ParametersFactoryInterface'); } } } diff --git a/src/Attributes/RequestBody.php b/src/Attributes/RequestBody.php index a8645fb..ef18fd2 100644 --- a/src/Attributes/RequestBody.php +++ b/src/Attributes/RequestBody.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; #[Attribute(Attribute::TARGET_METHOD)] class RequestBody @@ -13,10 +13,10 @@ class RequestBody public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\RequestBodies\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\RequestBodies\\' . $factory; - if (! is_a($this->factory, RequestBodyFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactory'); + if (!is_a($this->factory, RequestBodyFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactoryInterface'); } } } diff --git a/src/Attributes/Response.php b/src/Attributes/Response.php index a5f82d2..445674b 100644 --- a/src/Attributes/Response.php +++ b/src/Attributes/Response.php @@ -4,7 +4,7 @@ use Attribute; use InvalidArgumentException; -use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ResponseFactoryInterface; #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Response @@ -17,10 +17,10 @@ class Response public function __construct(string $factory, int $statusCode = null, string $description = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Responses\\'.$factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Responses\\' . $factory; - if (! is_a($this->factory, ResponseFactory::class, true)) { - throw new InvalidArgumentException('Factory class must be instance of ResponseFactory'); + if (!is_a($this->factory, ResponseFactoryInterface::class, true)) { + throw new InvalidArgumentException('Factory class must be instance of ResponseFactoryInterface'); } $this->statusCode = $statusCode; diff --git a/src/Builders/Components/CallbacksBuilder.php b/src/Builders/Components/CallbacksBuilder.php index 0e0e79e..9fb63a6 100644 --- a/src/Builders/Components/CallbacksBuilder.php +++ b/src/Builders/Components/CallbacksBuilder.php @@ -2,8 +2,8 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; +use Vyuldashev\LaravelOpenApi\Contracts\CallbackFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\CallbackFactory; use Vyuldashev\LaravelOpenApi\Generator; class CallbacksBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, CallbackFactory::class, true) && + is_a($class, CallbackFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var CallbackFactory $instance */ + /** @var CallbackFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/RequestBodiesBuilder.php b/src/Builders/Components/RequestBodiesBuilder.php index be6fe43..255e904 100644 --- a/src/Builders/Components/RequestBodiesBuilder.php +++ b/src/Builders/Components/RequestBodiesBuilder.php @@ -2,8 +2,8 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; use Vyuldashev\LaravelOpenApi\Generator; class RequestBodiesBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, RequestBodyFactory::class, true) && + is_a($class, RequestBodyFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var RequestBodyFactory $instance */ + /** @var RequestBodyFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/ResponsesBuilder.php b/src/Builders/Components/ResponsesBuilder.php index 86ee458..fa73864 100644 --- a/src/Builders/Components/ResponsesBuilder.php +++ b/src/Builders/Components/ResponsesBuilder.php @@ -2,8 +2,8 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; +use Vyuldashev\LaravelOpenApi\Contracts\ResponseFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory; use Vyuldashev\LaravelOpenApi\Generator; class ResponsesBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, ResponseFactory::class, true) && + is_a($class, ResponseFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var ResponseFactory $instance */ + /** @var ResponseFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/SchemasBuilder.php b/src/Builders/Components/SchemasBuilder.php index 7c1df5f..6081b6b 100644 --- a/src/Builders/Components/SchemasBuilder.php +++ b/src/Builders/Components/SchemasBuilder.php @@ -3,7 +3,7 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory; +use Vyuldashev\LaravelOpenApi\Contracts\SchemaFactoryInterface; use Vyuldashev\LaravelOpenApi\Generator; class SchemasBuilder extends Builder @@ -13,11 +13,11 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array return $this->getAllClasses($collection) ->filter(static function ($class) { return - is_a($class, SchemaFactory::class, true) && + is_a($class, SchemaFactoryInterface::class, true) && is_a($class, Reusable::class, true); }) ->map(static function ($class) { - /** @var SchemaFactory $instance */ + /** @var SchemaFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/Components/SecuritySchemesBuilder.php b/src/Builders/Components/SecuritySchemesBuilder.php index b7a18fe..7b45147 100644 --- a/src/Builders/Components/SecuritySchemesBuilder.php +++ b/src/Builders/Components/SecuritySchemesBuilder.php @@ -2,7 +2,7 @@ namespace Vyuldashev\LaravelOpenApi\Builders\Components; -use Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory; +use Vyuldashev\LaravelOpenApi\Contracts\SecuritySchemeFactoryInterface; use Vyuldashev\LaravelOpenApi\Generator; class SecuritySchemesBuilder extends Builder @@ -11,10 +11,10 @@ public function build(string $collection = Generator::COLLECTION_DEFAULT): array { return $this->getAllClasses($collection) ->filter(static function ($class) { - return is_a($class, SecuritySchemeFactory::class, true); + return is_a($class, SecuritySchemeFactoryInterface::class, true); }) ->map(static function ($class) { - /** @var SecuritySchemeFactory $instance */ + /** @var SecuritySchemeFactoryInterface $instance */ $instance = app($class); return $instance->build(); diff --git a/src/Builders/ExtensionsBuilder.php b/src/Builders/ExtensionsBuilder.php index 5fa295a..8329ce5 100644 --- a/src/Builders/ExtensionsBuilder.php +++ b/src/Builders/ExtensionsBuilder.php @@ -5,7 +5,7 @@ use GoldSpecDigital\ObjectOrientedOAS\Objects\BaseObject; use Illuminate\Support\Collection; use Vyuldashev\LaravelOpenApi\Attributes\Extension as ExtensionAttribute; -use Vyuldashev\LaravelOpenApi\Factories\ExtensionFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ExtensionFactoryInterface; class ExtensionsBuilder { @@ -15,7 +15,7 @@ public function build(BaseObject $object, Collection $attributes): void ->filter(static fn (object $attribute) => $attribute instanceof ExtensionAttribute) ->each(static function (ExtensionAttribute $attribute) use ($object): void { if ($attribute->factory) { - /** @var ExtensionFactory $factory */ + /** @var ExtensionFactoryInterface $factory */ $factory = app($attribute->factory); $key = $factory->key(); $value = $factory->value(); diff --git a/src/Builders/Paths/Operation/ParametersBuilder.php b/src/Builders/Paths/Operation/ParametersBuilder.php index 2333690..55e7ba1 100644 --- a/src/Builders/Paths/Operation/ParametersBuilder.php +++ b/src/Builders/Paths/Operation/ParametersBuilder.php @@ -9,7 +9,7 @@ use phpDocumentor\Reflection\DocBlock\Tags\Param; use ReflectionParameter; use Vyuldashev\LaravelOpenApi\Attributes\Parameters; -use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory; +use Vyuldashev\LaravelOpenApi\Contracts\ParametersFactoryInterface; use Vyuldashev\LaravelOpenApi\RouteInformation; use Vyuldashev\LaravelOpenApi\SchemaHelpers; @@ -60,7 +60,7 @@ protected function buildAttribute(RouteInformation $route): Collection $parameters = $route->actionAttributes->first(static fn ($attribute) => $attribute instanceof Parameters, []); if ($parameters) { - /** @var ParametersFactory $parametersFactory */ + /** @var ParametersFactoryInterface $parametersFactory */ $parametersFactory = app($parameters->factory); $parameters = $parametersFactory->build(); diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index da55879..c015e9c 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -4,8 +4,8 @@ use GoldSpecDigital\ObjectOrientedOAS\Objects\RequestBody; use Vyuldashev\LaravelOpenApi\Attributes\RequestBody as RequestBodyAttribute; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; use Vyuldashev\LaravelOpenApi\RouteInformation; class RequestBodyBuilder @@ -16,13 +16,13 @@ public function build(RouteInformation $route): ?RequestBody $requestBody = $route->actionAttributes->first(static fn (object $attribute) => $attribute instanceof RequestBodyAttribute); if ($requestBody) { - /** @var RequestBodyFactory $requestBodyFactory */ + /** @var RequestBodyFactoryInterface $requestBodyFactory */ $requestBodyFactory = app($requestBody->factory); $requestBody = $requestBodyFactory->build(); if ($requestBodyFactory instanceof Reusable) { - return RequestBody::ref('#/components/requestBodies/'.$requestBody->objectId); + return RequestBody::ref('#/components/requestBodies/' . $requestBody->objectId); } } diff --git a/src/Concerns/Referencable.php b/src/Concerns/Referencable.php index fd36525..26b3cae 100644 --- a/src/Concerns/Referencable.php +++ b/src/Concerns/Referencable.php @@ -4,13 +4,13 @@ use GoldSpecDigital\ObjectOrientedOAS\Objects\Schema; use InvalidArgumentException; +use Vyuldashev\LaravelOpenApi\Contracts\CallbackFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\ParametersFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\RequestBodyFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\ResponseFactoryInterface; use Vyuldashev\LaravelOpenApi\Contracts\Reusable; -use Vyuldashev\LaravelOpenApi\Factories\CallbackFactory; -use Vyuldashev\LaravelOpenApi\Factories\ParametersFactory; -use Vyuldashev\LaravelOpenApi\Factories\RequestBodyFactory; -use Vyuldashev\LaravelOpenApi\Factories\ResponseFactory; -use Vyuldashev\LaravelOpenApi\Factories\SchemaFactory; -use Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory; +use Vyuldashev\LaravelOpenApi\Contracts\SchemaFactoryInterface; +use Vyuldashev\LaravelOpenApi\Contracts\SecuritySchemeFactoryInterface; trait Referencable { @@ -18,26 +18,26 @@ public static function ref(?string $objectId = null): Schema { $instance = app(static::class); - if (! $instance instanceof Reusable) { - throw new InvalidArgumentException('"'.static::class.'" must implement "'.Reusable::class.'" in order to be referencable.'); + if (!$instance instanceof Reusable) { + throw new InvalidArgumentException('"' . static::class . '" must implement "' . Reusable::class . '" in order to be referencable.'); } $baseRef = null; - if ($instance instanceof CallbackFactory) { + if ($instance instanceof CallbackFactoryInterface) { $baseRef = '#/components/callbacks/'; - } elseif ($instance instanceof ParametersFactory) { + } elseif ($instance instanceof ParametersFactoryInterface) { $baseRef = '#/components/parameters/'; - } elseif ($instance instanceof RequestBodyFactory) { + } elseif ($instance instanceof RequestBodyFactoryInterface) { $baseRef = '#/components/requestBodies/'; - } elseif ($instance instanceof ResponseFactory) { + } elseif ($instance instanceof ResponseFactoryInterface) { $baseRef = '#/components/responses/'; - } elseif ($instance instanceof SchemaFactory) { + } elseif ($instance instanceof SchemaFactoryInterface) { $baseRef = '#/components/schemas/'; - } elseif ($instance instanceof SecuritySchemeFactory) { + } elseif ($instance instanceof SecuritySchemeFactoryInterface) { $baseRef = '#/components/securitySchemes/'; } - return Schema::ref($baseRef.$instance->build()->objectId, $objectId); + return Schema::ref($baseRef . $instance->build()->objectId, $objectId); } } diff --git a/src/Contracts/CallbackFactoryInterface.php b/src/Contracts/CallbackFactoryInterface.php new file mode 100644 index 0000000..0a5233c --- /dev/null +++ b/src/Contracts/CallbackFactoryInterface.php @@ -0,0 +1,12 @@ +set('openapi.locations.schemas', [ - __DIR__.'/../examples/petstore/OpenApi/Schemas', + __DIR__ . '/../examples/petstore/OpenApi/Schemas', ]); } @@ -80,5 +81,20 @@ public function testGenerate(): void ], ], ], $spec['components']['schemas']['Pet']); + + self::assertEquals([ + 'summary' => 'Create pet.', + 'operationId' => 'createPet', + 'requestBody' => [ + "description" => "Pet data", + "content" => [ + "application/json" => [ + "schema" => [ + '$ref' => "#/components/schemas/Pet", + ] + ], + ], + ], + ], $spec['paths']['/pet']['post']); } } From 2d735f3af54c54cd8d3e336e6d1d07e308fdb06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 2 Mar 2021 08:42:09 +0100 Subject: [PATCH 13/20] Add custom data to Parameters, RequestBody and Response --- examples/petstore/OpenApi/Parameters/ListPetsParameters.php | 2 +- .../petstore/OpenApi/RequestBodies/CreatePetRequestBody.php | 2 +- .../petstore/OpenApi/Responses/ErrorValidationResponse.php | 2 +- examples/petstore/PetController.php | 6 +++--- src/Attributes/Parameters.php | 4 +++- src/Attributes/RequestBody.php | 4 +++- src/Attributes/Response.php | 5 ++++- src/Builders/Paths/Operation/ParametersBuilder.php | 3 ++- src/Builders/Paths/Operation/RequestBodyBuilder.php | 3 ++- src/Builders/Paths/Operation/ResponsesBuilder.php | 4 +++- tests/PetstoreTest.php | 4 ++-- 11 files changed, 25 insertions(+), 14 deletions(-) diff --git a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php index ff220f2..b003382 100644 --- a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php +++ b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php @@ -17,7 +17,7 @@ public function build(): array Parameter::query() ->name('limit') - ->description('How many items to return at one time (max 100)') + ->description('How many items to return at one time (max 100) ' . $this->data) ->required(false) ->schema( Schema::integer()->format(Schema::FORMAT_INT32) diff --git a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php index f608afc..e31f12f 100644 --- a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php +++ b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php @@ -18,7 +18,7 @@ class CreatePetRequestBody implements RequestBodyFactoryInterface public function build(): RequestBody { return RequestBody::create('UserCreate') - ->description('Pet data') + ->description($this->data['custom']) ->content( MediaType::json()->schema(PetSchema::ref()) ); diff --git a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php index 2b28287..f8b7d0a 100644 --- a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php +++ b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php @@ -13,7 +13,7 @@ class ErrorValidationResponse extends ResponseFactory implements Reusable public function build(): Response { $response = Schema::object()->properties( - Schema::string('message')->example('The given data was invalid.'), + Schema::string('message')->example('The given data was invalid. ' . $this->data), Schema::object('errors') ->additionalProperties( Schema::array()->items(Schema::string()) diff --git a/examples/petstore/PetController.php b/examples/petstore/PetController.php index 11bbb27..0a07d43 100644 --- a/examples/petstore/PetController.php +++ b/examples/petstore/PetController.php @@ -14,8 +14,8 @@ class PetController * List all pets. */ #[OpenApi\Operation('listPets')] - #[OpenApi\Parameters(ListPetsParameters::class)] - #[OpenApi\Response(ErrorValidationResponse::class, 422)] + #[OpenApi\Parameters(ListPetsParameters::class, "Parameters custom data")] + #[OpenApi\Response(ErrorValidationResponse::class, 422, "", "Response custom data")] public function index() { } @@ -24,7 +24,7 @@ public function index() * Create pet. */ #[OpenApi\Operation('createPet')] - #[OpenApi\RequestBody(CreatePetRequestBody::class)] + #[OpenApi\RequestBody(CreatePetRequestBody::class, ["custom" => "My custom data"])] public function create() { } diff --git a/src/Attributes/Parameters.php b/src/Attributes/Parameters.php index 0d4df6d..268318e 100644 --- a/src/Attributes/Parameters.php +++ b/src/Attributes/Parameters.php @@ -10,10 +10,12 @@ class Parameters { public string $factory; + public $data; - public function __construct(string $factory) + public function __construct(string $factory, $data = null) { $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Parameters\\' . $factory; + $this->data = $data; if (!is_a($this->factory, ParametersFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ParametersFactoryInterface'); diff --git a/src/Attributes/RequestBody.php b/src/Attributes/RequestBody.php index ef18fd2..59cb148 100644 --- a/src/Attributes/RequestBody.php +++ b/src/Attributes/RequestBody.php @@ -10,10 +10,12 @@ class RequestBody { public string $factory; + public $data; - public function __construct(string $factory) + public function __construct(string $factory, $data = null) { $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\RequestBodies\\' . $factory; + $this->data = $data; if (!is_a($this->factory, RequestBodyFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactoryInterface'); diff --git a/src/Attributes/Response.php b/src/Attributes/Response.php index 445674b..34aa664 100644 --- a/src/Attributes/Response.php +++ b/src/Attributes/Response.php @@ -15,9 +15,12 @@ class Response public ?string $description; - public function __construct(string $factory, int $statusCode = null, string $description = null) + public $data; + + public function __construct(string $factory, int $statusCode = null, string $description = null, $data = null) { $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Responses\\' . $factory; + $this->data = $data; if (!is_a($this->factory, ResponseFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ResponseFactoryInterface'); diff --git a/src/Builders/Paths/Operation/ParametersBuilder.php b/src/Builders/Paths/Operation/ParametersBuilder.php index 55e7ba1..f652877 100644 --- a/src/Builders/Paths/Operation/ParametersBuilder.php +++ b/src/Builders/Paths/Operation/ParametersBuilder.php @@ -62,7 +62,8 @@ protected function buildAttribute(RouteInformation $route): Collection if ($parameters) { /** @var ParametersFactoryInterface $parametersFactory */ $parametersFactory = app($parameters->factory); - + // little bit magic, add custom data into factory + $parametersFactory->data = $parameters->data; $parameters = $parametersFactory->build(); } diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index c015e9c..c395607 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -18,7 +18,8 @@ public function build(RouteInformation $route): ?RequestBody if ($requestBody) { /** @var RequestBodyFactoryInterface $requestBodyFactory */ $requestBodyFactory = app($requestBody->factory); - + // little bit magic, add custom data into factory + $requestBodyFactory->data = $requestBody->data; $requestBody = $requestBodyFactory->build(); if ($requestBodyFactory instanceof Reusable) { diff --git a/src/Builders/Paths/Operation/ResponsesBuilder.php b/src/Builders/Paths/Operation/ResponsesBuilder.php index f43d374..b374828 100644 --- a/src/Builders/Paths/Operation/ResponsesBuilder.php +++ b/src/Builders/Paths/Operation/ResponsesBuilder.php @@ -15,10 +15,12 @@ public function build(RouteInformation $route): array ->filter(static fn (object $attribute) => $attribute instanceof ResponseAttribute) ->map(static function (ResponseAttribute $attribute) { $factory = app($attribute->factory); + // little bit magic, add custom data into factory + $factory->data = $attribute->data; $response = $factory->build(); if ($factory instanceof Reusable) { - return Response::ref('#/components/responses/'.$response->objectId) + return Response::ref('#/components/responses/' . $response->objectId) ->statusCode($attribute->statusCode) ->description($attribute->description); } diff --git a/tests/PetstoreTest.php b/tests/PetstoreTest.php index ab82843..0255650 100644 --- a/tests/PetstoreTest.php +++ b/tests/PetstoreTest.php @@ -43,7 +43,7 @@ public function testGenerate(): void [ 'name' => 'limit', 'in' => 'query', - 'description' => 'How many items to return at one time (max 100)', + 'description' => 'How many items to return at one time (max 100) Parameters custom data', 'required' => false, 'schema' => [ 'format' => 'int32', @@ -86,7 +86,7 @@ public function testGenerate(): void 'summary' => 'Create pet.', 'operationId' => 'createPet', 'requestBody' => [ - "description" => "Pet data", + "description" => "My custom data", "content" => [ "application/json" => [ "schema" => [ From 43e3156e8c4642e958a0d421ffc4423cf10312fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 2 Mar 2021 08:43:34 +0100 Subject: [PATCH 14/20] Add Makefile with docker --- Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5087f9a --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +#!make + +.PHONY: tests + +COMPOSE_IMAGE = composer:2 +PHP_IMAGE=php:8 + +composer: + docker pull $(DOCKER_COMPOSE) + docker run --rm --interactive --tty --user $(id -u):$(id -g) -w /app --volume `pwd`:/app $(COMPOSE_IMAGE) composer $(P) + +composer_install: + make composer P="install" + +phpunit: + docker pull $(PHP_IMAGE) + docker run --rm -it --user $(id -u):$(id -g) -w /app --volume `pwd`:/app $(PHP_IMAGE) ./vendor/bin/phpunit $(P) + +# run all php unit tests +tests: + make phpunit P=tests \ No newline at end of file From 67fd49b08763ef12604444bbdd0a0487b945d949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Wed, 3 Mar 2021 11:29:23 +0100 Subject: [PATCH 15/20] package name update --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index da3e7ef..423b384 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "vyuldashev/laravel-openapi", + "name": "ogsoft/laravel-openapi", "description": "Generate OpenAPI Specification for Laravel Applications", "keywords": [ "laravel", From ef2a2c53499ce54958fd2d9bd8e9af1f47174a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 12 Oct 2021 09:28:46 +0200 Subject: [PATCH 16/20] format fix --- .../OpenApi/Parameters/ListPetsParameters.php | 2 +- .../OpenApi/RequestBodies/CreatePetRequestBody.php | 6 +----- .../OpenApi/Responses/ErrorValidationResponse.php | 2 +- examples/petstore/PetController.php | 6 +++--- src/Attributes/Callback.php | 4 ++-- src/Attributes/Extension.php | 4 ++-- src/Attributes/Parameters.php | 4 ++-- src/Attributes/RequestBody.php | 4 ++-- src/Attributes/Response.php | 4 ++-- .../Paths/Operation/RequestBodyBuilder.php | 2 +- src/Builders/Paths/Operation/ResponsesBuilder.php | 2 +- src/Concerns/Referencable.php | 6 +++--- src/Contracts/CallbackFactoryInterface.php | 4 +--- src/Contracts/ExtensionFactoryInterface.php | 4 +--- src/Contracts/ParametersFactoryInterface.php | 4 +--- src/Contracts/RequestBodyFactoryInterface.php | 7 ++----- src/Contracts/ResponseFactoryInterface.php | 4 +--- src/Contracts/SchemaFactoryInterface.php | 4 +--- src/Contracts/SecuritySchemeFactoryInterface.php | 4 +--- tests/PetstoreTest.php | 14 +++++++------- 20 files changed, 36 insertions(+), 55 deletions(-) diff --git a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php index b003382..c3be644 100644 --- a/examples/petstore/OpenApi/Parameters/ListPetsParameters.php +++ b/examples/petstore/OpenApi/Parameters/ListPetsParameters.php @@ -17,7 +17,7 @@ public function build(): array Parameter::query() ->name('limit') - ->description('How many items to return at one time (max 100) ' . $this->data) + ->description('How many items to return at one time (max 100) '.$this->data) ->required(false) ->schema( Schema::integer()->format(Schema::FORMAT_INT32) diff --git a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php index e31f12f..17799f6 100644 --- a/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php +++ b/examples/petstore/OpenApi/RequestBodies/CreatePetRequestBody.php @@ -1,9 +1,7 @@ schema(PetSchema::ref()) ); } - -} \ No newline at end of file +} diff --git a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php index f8b7d0a..9604094 100644 --- a/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php +++ b/examples/petstore/OpenApi/Responses/ErrorValidationResponse.php @@ -13,7 +13,7 @@ class ErrorValidationResponse extends ResponseFactory implements Reusable public function build(): Response { $response = Schema::object()->properties( - Schema::string('message')->example('The given data was invalid. ' . $this->data), + Schema::string('message')->example('The given data was invalid. '.$this->data), Schema::object('errors') ->additionalProperties( Schema::array()->items(Schema::string()) diff --git a/examples/petstore/PetController.php b/examples/petstore/PetController.php index 0a07d43..7ce92ba 100644 --- a/examples/petstore/PetController.php +++ b/examples/petstore/PetController.php @@ -14,8 +14,8 @@ class PetController * List all pets. */ #[OpenApi\Operation('listPets')] - #[OpenApi\Parameters(ListPetsParameters::class, "Parameters custom data")] - #[OpenApi\Response(ErrorValidationResponse::class, 422, "", "Response custom data")] + #[OpenApi\Parameters(ListPetsParameters::class, 'Parameters custom data')] + #[OpenApi\Response(ErrorValidationResponse::class, 422, '', 'Response custom data')] public function index() { } @@ -24,7 +24,7 @@ public function index() * Create pet. */ #[OpenApi\Operation('createPet')] - #[OpenApi\RequestBody(CreatePetRequestBody::class, ["custom" => "My custom data"])] + #[OpenApi\RequestBody(CreatePetRequestBody::class, ['custom' => 'My custom data'])] public function create() { } diff --git a/src/Attributes/Callback.php b/src/Attributes/Callback.php index 5a1ea83..c3149da 100644 --- a/src/Attributes/Callback.php +++ b/src/Attributes/Callback.php @@ -13,9 +13,9 @@ class Callback public function __construct(string $factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Callbacks\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Callbacks\\'.$factory; - if (!is_a($this->factory, CallbackFactoryInterface::class, true)) { + if (! is_a($this->factory, CallbackFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of CallbackFactoryInterface'); } } diff --git a/src/Attributes/Extension.php b/src/Attributes/Extension.php index e678da7..2de21db 100644 --- a/src/Attributes/Extension.php +++ b/src/Attributes/Extension.php @@ -16,9 +16,9 @@ class Extension public function __construct(string $factory = null, string $key = null, string $value = null) { if ($factory) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Extensions\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Extensions\\'.$factory; - if (!is_a($this->factory, ExtensionFactoryInterface::class, true)) { + if (! is_a($this->factory, ExtensionFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ExtensionFactoryInterface'); } } diff --git a/src/Attributes/Parameters.php b/src/Attributes/Parameters.php index 268318e..776a980 100644 --- a/src/Attributes/Parameters.php +++ b/src/Attributes/Parameters.php @@ -14,10 +14,10 @@ class Parameters public function __construct(string $factory, $data = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Parameters\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Parameters\\'.$factory; $this->data = $data; - if (!is_a($this->factory, ParametersFactoryInterface::class, true)) { + if (! is_a($this->factory, ParametersFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ParametersFactoryInterface'); } } diff --git a/src/Attributes/RequestBody.php b/src/Attributes/RequestBody.php index 59cb148..cb01f8f 100644 --- a/src/Attributes/RequestBody.php +++ b/src/Attributes/RequestBody.php @@ -14,10 +14,10 @@ class RequestBody public function __construct(string $factory, $data = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\RequestBodies\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\RequestBodies\\'.$factory; $this->data = $data; - if (!is_a($this->factory, RequestBodyFactoryInterface::class, true)) { + if (! is_a($this->factory, RequestBodyFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of RequestBodyFactoryInterface'); } } diff --git a/src/Attributes/Response.php b/src/Attributes/Response.php index 34aa664..b5de7ad 100644 --- a/src/Attributes/Response.php +++ b/src/Attributes/Response.php @@ -19,10 +19,10 @@ class Response public function __construct(string $factory, int $statusCode = null, string $description = null, $data = null) { - $this->factory = class_exists($factory) ? $factory : app()->getNamespace() . 'OpenApi\\Responses\\' . $factory; + $this->factory = class_exists($factory) ? $factory : app()->getNamespace().'OpenApi\\Responses\\'.$factory; $this->data = $data; - if (!is_a($this->factory, ResponseFactoryInterface::class, true)) { + if (! is_a($this->factory, ResponseFactoryInterface::class, true)) { throw new InvalidArgumentException('Factory class must be instance of ResponseFactoryInterface'); } diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index c395607..1b4a5ff 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -23,7 +23,7 @@ public function build(RouteInformation $route): ?RequestBody $requestBody = $requestBodyFactory->build(); if ($requestBodyFactory instanceof Reusable) { - return RequestBody::ref('#/components/requestBodies/' . $requestBody->objectId); + return RequestBody::ref('#/components/requestBodies/'.$requestBody->objectId); } } diff --git a/src/Builders/Paths/Operation/ResponsesBuilder.php b/src/Builders/Paths/Operation/ResponsesBuilder.php index b374828..b6aeb11 100644 --- a/src/Builders/Paths/Operation/ResponsesBuilder.php +++ b/src/Builders/Paths/Operation/ResponsesBuilder.php @@ -20,7 +20,7 @@ public function build(RouteInformation $route): array $response = $factory->build(); if ($factory instanceof Reusable) { - return Response::ref('#/components/responses/' . $response->objectId) + return Response::ref('#/components/responses/'.$response->objectId) ->statusCode($attribute->statusCode) ->description($attribute->description); } diff --git a/src/Concerns/Referencable.php b/src/Concerns/Referencable.php index 26b3cae..fdf4209 100644 --- a/src/Concerns/Referencable.php +++ b/src/Concerns/Referencable.php @@ -18,8 +18,8 @@ public static function ref(?string $objectId = null): Schema { $instance = app(static::class); - if (!$instance instanceof Reusable) { - throw new InvalidArgumentException('"' . static::class . '" must implement "' . Reusable::class . '" in order to be referencable.'); + if (! $instance instanceof Reusable) { + throw new InvalidArgumentException('"'.static::class.'" must implement "'.Reusable::class.'" in order to be referencable.'); } $baseRef = null; @@ -38,6 +38,6 @@ public static function ref(?string $objectId = null): Schema $baseRef = '#/components/securitySchemes/'; } - return Schema::ref($baseRef . $instance->build()->objectId, $objectId); + return Schema::ref($baseRef.$instance->build()->objectId, $objectId); } } diff --git a/src/Contracts/CallbackFactoryInterface.php b/src/Contracts/CallbackFactoryInterface.php index 0a5233c..df14204 100644 --- a/src/Contracts/CallbackFactoryInterface.php +++ b/src/Contracts/CallbackFactoryInterface.php @@ -1,12 +1,10 @@ set('openapi.locations.schemas', [ - __DIR__ . '/../examples/petstore/OpenApi/Schemas', + __DIR__.'/../examples/petstore/OpenApi/Schemas', ]); } @@ -86,12 +86,12 @@ public function testGenerate(): void 'summary' => 'Create pet.', 'operationId' => 'createPet', 'requestBody' => [ - "description" => "My custom data", - "content" => [ - "application/json" => [ - "schema" => [ - '$ref' => "#/components/schemas/Pet", - ] + 'description' => 'My custom data', + 'content' => [ + 'application/json' => [ + 'schema' => [ + '$ref' => '#/components/schemas/Pet', + ], ], ], ], From bcd1201211b72f2a81cbad1266e600957334741d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Mazura?= Date: Tue, 12 Oct 2021 09:29:34 +0200 Subject: [PATCH 17/20] format fix --- src/Contracts/RequestBodyFactoryInterface.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Contracts/RequestBodyFactoryInterface.php b/src/Contracts/RequestBodyFactoryInterface.php index cacdf01..2f4cb0b 100644 --- a/src/Contracts/RequestBodyFactoryInterface.php +++ b/src/Contracts/RequestBodyFactoryInterface.php @@ -7,6 +7,7 @@ /** * Interface RequestBodyFactoryInterface. + * * @var $data */ interface RequestBodyFactoryInterface From 10b603ca53b59981c5457ac8473d1a890418ba46 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:18:28 +0200 Subject: [PATCH 18/20] Add security to Operation Attribute --- src/Attributes/Operation.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Attributes/Operation.php b/src/Attributes/Operation.php index e69efcf..8c02de7 100644 --- a/src/Attributes/Operation.php +++ b/src/Attributes/Operation.php @@ -11,6 +11,9 @@ class Operation { public ?string $id; + /** @var array */ + public array $security; + /** @var array */ public array $tags; @@ -18,6 +21,7 @@ class Operation public ?string $method; +<<<<<<< HEAD /** * @param string|null $id * @param array $tags @@ -27,9 +31,13 @@ class Operation * @throws InvalidArgumentException */ public function __construct(string $id = null, array $tags = [], string $security = null, string $method = null) +======= + public function __construct(string $id = null, array $tags = [], array $security = [], string $method = null) +>>>>>>> 91eae28 (Add security to Operation Attribute) { $this->id = $id; $this->tags = $tags; + $this->security = $security; $this->method = $method; if ($security === '') { From 019d11e5bf5d9f1eeeac6acf48f7f3e52e6bb3e9 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:31:55 +0200 Subject: [PATCH 19/20] Update Operation.php --- src/Attributes/Operation.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Attributes/Operation.php b/src/Attributes/Operation.php index 8c02de7..c32b4f3 100644 --- a/src/Attributes/Operation.php +++ b/src/Attributes/Operation.php @@ -11,9 +11,6 @@ class Operation { public ?string $id; - /** @var array */ - public array $security; - /** @var array */ public array $tags; @@ -21,6 +18,7 @@ class Operation public ?string $method; +<<<<<<< HEAD <<<<<<< HEAD /** * @param string|null $id @@ -34,12 +32,22 @@ public function __construct(string $id = null, array $tags = [], string $securit ======= public function __construct(string $id = null, array $tags = [], array $security = [], string $method = null) >>>>>>> 91eae28 (Add security to Operation Attribute) +======= + /** + * @param string|null $id + * @param array $tags + * @param \Vyuldashev\LaravelOpenApi\Factories\SecuritySchemeFactory|string|null $security + * @param string|null $method + * @throws InvalidArgumentException + */ + public function __construct(string $id = null, array $tags = [], string $security = null, string $method = null) +>>>>>>> 250ae9f (Update Operation.php) { $this->id = $id; $this->tags = $tags; - $this->security = $security; $this->method = $method; +<<<<<<< HEAD if ($security === '') { //user wants to turn off security on this operation $this->security = $security; @@ -53,6 +61,14 @@ public function __construct(string $id = null, array $tags = [], array $security if (! is_a($this->security, SecuritySchemeFactory::class, true)) { throw new InvalidArgumentException( sprintf('Security class is either not declared or is not an instance of %s', SecuritySchemeFactory::class) +======= + if ($security) { + $this->security = class_exists($security) ? $security : app()->getNamespace() . 'OpenApi\\SecuritySchemes\\' . $security . 'SecurityScheme'; + + if (!is_a($this->security, SecuritySchemeFactory::class, true)) { + throw new InvalidArgumentException( + sprintf('Security class is either not declared or is not an instance of [%s]', SecuritySchemeFactory::class) +>>>>>>> 250ae9f (Update Operation.php) ); } } From b443c6a2020de1097d542360efadde716fbe80e9 Mon Sep 17 00:00:00 2001 From: qwasyx0 <43924784+qwasyx0@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:32:40 +0200 Subject: [PATCH 20/20] Create SecurityBuilder.php --- .../Paths/Operation/SecurityBuilder.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Builders/Paths/Operation/SecurityBuilder.php b/src/Builders/Paths/Operation/SecurityBuilder.php index 2a02a27..51c1a34 100644 --- a/src/Builders/Paths/Operation/SecurityBuilder.php +++ b/src/Builders/Paths/Operation/SecurityBuilder.php @@ -8,6 +8,7 @@ class SecurityBuilder { +<<<<<<< HEAD public function build(RouteInformation $route): array { return $route->actionAttributes @@ -26,4 +27,20 @@ public function build(RouteInformation $route): array ->values() ->toArray(); } +======= + public function build(RouteInformation $route): array + { + return $route->actionAttributes + ->filter(static fn (object $attribute) => $attribute instanceof OperationAttribute) + ->filter(static fn (OperationAttribute $attribute) => isset($attribute->security)) + ->map(static function (OperationAttribute $attribute) { + $security = app($attribute->security); + $scheme = $security->build(); + + return SecurityRequirement::create()->securityScheme($scheme); + }) + ->values() + ->toArray(); + } +>>>>>>> 4856d12 (Create SecurityBuilder.php) }