From 2712c49d8261b81cec7f3f6f9c96f8f93ac6be1d Mon Sep 17 00:00:00 2001 From: DerManoMann Date: Mon, 15 Jul 2024 13:08:31 +1200 Subject: [PATCH 1/3] Remove annotation based `schema-query-parameter` processor example in favour of the attribute version --- Examples/Readme.md | 9 +- .../SchemaQueryParameter.php | 84 ------------------- .../app/OpenApi.php | 17 ---- .../app/Product.php | 26 ------ .../app/ProductController.php | 54 ------------ .../scan.php | 29 ------- .../schema-query-parameter.yaml | 69 --------------- .../SchemaQueryParameter.php | 76 +++++++++-------- .../schema-query-parameter/app/OpenApi.php | 10 +-- .../schema-query-parameter/app/Product.php | 40 ++++----- .../app/ProductController.php | 75 +++++++++-------- .../schema-query-parameter.yaml | 23 +++-- .../sort-components/SortComponents.php | 2 +- 13 files changed, 119 insertions(+), 395 deletions(-) delete mode 100644 Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php delete mode 100644 Examples/processors/schema-query-parameter-attributes/app/OpenApi.php delete mode 100644 Examples/processors/schema-query-parameter-attributes/app/Product.php delete mode 100644 Examples/processors/schema-query-parameter-attributes/app/ProductController.php delete mode 100644 Examples/processors/schema-query-parameter-attributes/scan.php delete mode 100644 Examples/processors/schema-query-parameter-attributes/schema-query-parameter.yaml diff --git a/Examples/Readme.md b/Examples/Readme.md index c53728591..fe7cbd4a2 100644 --- a/Examples/Readme.md +++ b/Examples/Readme.md @@ -61,13 +61,6 @@ class MyCustomProcessor * **schema-query-parameter processor** - A processor that takes a vendor tag (expecting a schema `#ref`) and injects all properties of that given schema as - query parameter to the [request definition](processors/schema-query-parameter/app/ProductController.php). - - [source](processors/schema-query-parameter) - -* **schema-query-parameter-attributes processor** - Same as the `schema-query-parameter` processor but uses php attributes instead of annotations. A processor that takes a vendor tag (expecting a schema `#ref`) and injects all properties of that given schema as query parameter to the [request definition](processors/schema-query-parameter-attributes/SchemaQueryParameter.php). @@ -76,6 +69,6 @@ class MyCustomProcessor * **sort-components processor** - A processor that sorts components so they appear in alphabetical order. + A processor that sorts components, so they appear in alphabetical order. [source](processors/sort-components) diff --git a/Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php b/Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php deleted file mode 100644 index d1fb56ecd..000000000 --- a/Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php +++ /dev/null @@ -1,84 +0,0 @@ -getAnnotationsOfType(Operation::class); - - foreach ($operations as $operation) { - if ($operation->x !== Generator::UNDEFINED && array_key_exists(self::REF, $operation->x)) { - if (!is_string($operation->x[self::REF])) { - throw new \InvalidArgumentException('Value of `x.' . self::REF . '` must be a string'); - } - - $schema = $analysis->getSchemaForSource($operation->x[self::REF]); - if (!$schema instanceof Schema) { - throw new \InvalidArgumentException('Value of `x.' . self::REF . "` contains reference to unknown schema: `{$operation->x[self::REF]}`"); - } - - $this->expandQueryArgs($operation, $schema); - $this->cleanUp($operation); - } - } - } - - /** - * Expand the given operation by injecting parameters for all properties of the given schema. - */ - private function expandQueryArgs(Operation $operation, Schema $schema): void - { - if ($schema->properties === Generator::UNDEFINED || !$schema->properties) { - return; - } - - $operation->parameters = $operation->parameters === Generator::UNDEFINED ? [] : $operation->parameters; - - foreach ($schema->properties as $property) { - $isNullable = $property->nullable !== Generator::UNDEFINED ? $property->nullable : false; - $schema = new Schema( - type: $property->format !== Generator::UNDEFINED ? $property->format : $property->type, - nullable: $isNullable - ); - $schema->_context = $operation->_context; // inherit context from operation, required to pretend to be a parameter - - $parameter = new Parameter( - name: $property->property, - description: $property->description !== Generator::UNDEFINED ? $property->description : null, - in: 'query', - required: !$isNullable, - schema: $schema, - example: $property->example, - ); - $parameter->_context = $operation->_context; // inherit context from operation, required to pretend to be a parameter - - $operation->parameters[] = $parameter; - } - } - - private function cleanUp(Operation $operation): void - { - unset($operation->x[self::REF]); - if (!$operation->x) { - $operation->x = Generator::UNDEFINED; - } - } -} diff --git a/Examples/processors/schema-query-parameter-attributes/app/OpenApi.php b/Examples/processors/schema-query-parameter-attributes/app/OpenApi.php deleted file mode 100644 index fe5875c45..000000000 --- a/Examples/processors/schema-query-parameter-attributes/app/OpenApi.php +++ /dev/null @@ -1,17 +0,0 @@ - Product::class], - )] - public function findProducts($id) - { - } -} diff --git a/Examples/processors/schema-query-parameter-attributes/scan.php b/Examples/processors/schema-query-parameter-attributes/scan.php deleted file mode 100644 index 83575d45c..000000000 --- a/Examples/processors/schema-query-parameter-attributes/scan.php +++ /dev/null @@ -1,29 +0,0 @@ -addPsr4('App\\', __DIR__ . '/app'); -// and our custom processor -$classLoader->addPsr4('SchemaQueryParameterProcessor\\', __DIR__); - -$insertMatch = function (array $pipes) { - foreach ($pipes as $ii => $pipe) { - if ($pipe instanceof BuildPaths) { - return $ii; - } - } - - return null; -}; - -$openapi = (new Generator()) - ->withProcessor(function (Pipeline $pipeline) use ($insertMatch) { $pipeline->insert(new SchemaQueryParameter(), $insertMatch); }) - ->generate([__DIR__ . '/app']); -// file_put_contents(__DIR__ . '/schema-query-parameter.yaml', $openapi->toYaml()); -echo $openapi->toYaml(); diff --git a/Examples/processors/schema-query-parameter-attributes/schema-query-parameter.yaml b/Examples/processors/schema-query-parameter-attributes/schema-query-parameter.yaml deleted file mode 100644 index 852a5708c..000000000 --- a/Examples/processors/schema-query-parameter-attributes/schema-query-parameter.yaml +++ /dev/null @@ -1,69 +0,0 @@ -openapi: 3.0.0 -info: - title: 'Example of using a custom processor in swagger-php' - version: 1.0.0 -paths: - '/products/{id}': - get: - tags: - - Products - operationId: 399b71a7672f0a46be1b5f4c120c355d - parameters: - - - name: id - in: path - required: true - responses: - '200': - description: 'A single product' - content: - application/json: - schema: - $ref: '#/components/schemas/Product' - /products/search: - get: - tags: - - Products - operationId: 178f74de3417eec20dee95709821e6ca - parameters: - - - name: id - in: query - required: true - schema: - type: integer - nullable: false - example: 43 - - - name: name - in: query - required: false - schema: - type: string - nullable: true - example: 'Lorem ipsum' - responses: - '200': - description: 'A single product' - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Product' -components: - schemas: - Product: - title: Product - description: 'A simple product model' - properties: - id: - title: 'The unique identifier of a product in our catalog.' - type: integer - example: 43 - name: - title: 'The name of the product.' - type: string - example: 'Lorem ipsum' - nullable: true - type: object diff --git a/Examples/processors/schema-query-parameter/SchemaQueryParameter.php b/Examples/processors/schema-query-parameter/SchemaQueryParameter.php index f0f5c62ac..d1fb56ecd 100644 --- a/Examples/processors/schema-query-parameter/SchemaQueryParameter.php +++ b/Examples/processors/schema-query-parameter/SchemaQueryParameter.php @@ -1,13 +1,14 @@ getAnnotationsOfType(Schema::class, true); /** @var Operation[] $operations */ $operations = $analysis->getAnnotationsOfType(Operation::class); foreach ($operations as $operation) { - if ($operation->x !== Generator::UNDEFINED && array_key_exists(self::X_QUERY_AGS_REF, $operation->x)) { - if ($schema = $this->schemaForRef($schemas, $operation->x[self::X_QUERY_AGS_REF])) { - $this->expandQueryArgs($operation, $schema); - $this->cleanUp($operation); + if ($operation->x !== Generator::UNDEFINED && array_key_exists(self::REF, $operation->x)) { + if (!is_string($operation->x[self::REF])) { + throw new \InvalidArgumentException('Value of `x.' . self::REF . '` must be a string'); } - } - } - } - /** - * Find schema for the given ref. - */ - protected function schemaForRef(array $schemas, string $ref) - { - foreach ($schemas as $schema) { - if (Components::ref($schema) === $ref) { - return $schema; + $schema = $analysis->getSchemaForSource($operation->x[self::REF]); + if (!$schema instanceof Schema) { + throw new \InvalidArgumentException('Value of `x.' . self::REF . "` contains reference to unknown schema: `{$operation->x[self::REF]}`"); + } + + $this->expandQueryArgs($operation, $schema); + $this->cleanUp($operation); } } - - return null; } /** * Expand the given operation by injecting parameters for all properties of the given schema. */ - protected function expandQueryArgs(Operation $operation, Schema $schema) + private function expandQueryArgs(Operation $operation, Schema $schema): void { - if ($schema->properties == Generator::UNDEFINED || !$schema->properties) { + if ($schema->properties === Generator::UNDEFINED || !$schema->properties) { return; } - $operation->parameters = $operation->parameters == Generator::UNDEFINED ? [] : $operation->parameters; + $operation->parameters = $operation->parameters === Generator::UNDEFINED ? [] : $operation->parameters; + foreach ($schema->properties as $property) { - $parameter = new Parameter([ - 'name' => $property->property, - 'in' => 'query', - 'required' => false, - ]); + $isNullable = $property->nullable !== Generator::UNDEFINED ? $property->nullable : false; + $schema = new Schema( + type: $property->format !== Generator::UNDEFINED ? $property->format : $property->type, + nullable: $isNullable + ); + $schema->_context = $operation->_context; // inherit context from operation, required to pretend to be a parameter + + $parameter = new Parameter( + name: $property->property, + description: $property->description !== Generator::UNDEFINED ? $property->description : null, + in: 'query', + required: !$isNullable, + schema: $schema, + example: $property->example, + ); + $parameter->_context = $operation->_context; // inherit context from operation, required to pretend to be a parameter + $operation->parameters[] = $parameter; } } - /** - * Clean up. - */ - protected function cleanUp($operation) + private function cleanUp(Operation $operation): void { - unset($operation->x[self::X_QUERY_AGS_REF]); + unset($operation->x[self::REF]); if (!$operation->x) { $operation->x = Generator::UNDEFINED; } diff --git a/Examples/processors/schema-query-parameter/app/OpenApi.php b/Examples/processors/schema-query-parameter/app/OpenApi.php index 1e7897894..fe5875c45 100644 --- a/Examples/processors/schema-query-parameter/app/OpenApi.php +++ b/Examples/processors/schema-query-parameter/app/OpenApi.php @@ -2,16 +2,16 @@ namespace App; +use OpenApi\Attributes as OA; + /** * Uses a custom processor `QueryArgsFromSchema` processor to convert a vendor extension into query parameters. * * The parameters are extracted from the schema referenced by the custom extension. - * - * @OA\Info( - * version="1.0.0", - * title="Example of using a custom processor in swagger-php", - * ) */ +#[OA\OpenApi( + info: new OA\Info(version: '1.0.0', title: 'Example of using a custom processor in swagger-php'), +)] class OpenApi { } diff --git a/Examples/processors/schema-query-parameter/app/Product.php b/Examples/processors/schema-query-parameter/app/Product.php index b250bfe4d..cbe492991 100644 --- a/Examples/processors/schema-query-parameter/app/Product.php +++ b/Examples/processors/schema-query-parameter/app/Product.php @@ -2,29 +2,25 @@ namespace App; -use OpenApi\Annotations as OA; +use OpenApi\Attributes as OA; -/** - * @OA\Schema( - * title="Product", - * description="A simple product model" - * ) - */ +#[OA\Schema( + title: 'Product', + description: 'A simple product model', +)] class Product { - /** - * The unique identifier of a product in our catalog. - * - * @var int - * - * @OA\Property(format="int64", example=1) - */ - public $id; - - /** - * @var string - * - * @OA\Property(format="int64", example=1) - */ - public $name; + public function __construct( + #[OA\Property( + title: 'The unique identifier of a product in our catalog.', + example: 43, + )] + public int $id, + #[OA\Property( + title: 'The name of the product.', + example: 'Lorem ipsum', + )] + public string|null $name, + ) { + } } diff --git a/Examples/processors/schema-query-parameter/app/ProductController.php b/Examples/processors/schema-query-parameter/app/ProductController.php index 8545c289d..5d9104931 100644 --- a/Examples/processors/schema-query-parameter/app/ProductController.php +++ b/Examples/processors/schema-query-parameter/app/ProductController.php @@ -1,48 +1,53 @@ Product::class], + )] public function findProducts($id) { } diff --git a/Examples/processors/schema-query-parameter/schema-query-parameter.yaml b/Examples/processors/schema-query-parameter/schema-query-parameter.yaml index c6a86d3d4..852a5708c 100644 --- a/Examples/processors/schema-query-parameter/schema-query-parameter.yaml +++ b/Examples/processors/schema-query-parameter/schema-query-parameter.yaml @@ -24,20 +24,27 @@ paths: get: tags: - Products - summary: 'Controller that takes all `Product` properties as query parameter.' operationId: 178f74de3417eec20dee95709821e6ca parameters: - name: id in: query - required: false + required: true + schema: + type: integer + nullable: false + example: 43 - name: name in: query required: false + schema: + type: string + nullable: true + example: 'Lorem ipsum' responses: '200': - description: 'A list of matching products' + description: 'A single product' content: application/json: schema: @@ -51,12 +58,12 @@ components: description: 'A simple product model' properties: id: - description: 'The unique identifier of a product in our catalog.' + title: 'The unique identifier of a product in our catalog.' type: integer - format: int64 - example: 1 + example: 43 name: + title: 'The name of the product.' type: string - format: int64 - example: 1 + example: 'Lorem ipsum' + nullable: true type: object diff --git a/Examples/processors/sort-components/SortComponents.php b/Examples/processors/sort-components/SortComponents.php index 92fee2683..0f21eb461 100644 --- a/Examples/processors/sort-components/SortComponents.php +++ b/Examples/processors/sort-components/SortComponents.php @@ -1,6 +1,6 @@ Date: Mon, 15 Jul 2024 13:20:45 +1200 Subject: [PATCH 2/3] Fix phpstan issues --- .../SchemaQueryParameter.php | 10 +++++----- phpstan-baseline.neon | 17 +---------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/Examples/processors/schema-query-parameter/SchemaQueryParameter.php b/Examples/processors/schema-query-parameter/SchemaQueryParameter.php index d1fb56ecd..785416f16 100644 --- a/Examples/processors/schema-query-parameter/SchemaQueryParameter.php +++ b/Examples/processors/schema-query-parameter/SchemaQueryParameter.php @@ -46,23 +46,23 @@ public function __invoke(Analysis $analysis): void */ private function expandQueryArgs(Operation $operation, Schema $schema): void { - if ($schema->properties === Generator::UNDEFINED || !$schema->properties) { + if (Generator::isDefault($schema->properties) || !$schema->properties) { return; } - $operation->parameters = $operation->parameters === Generator::UNDEFINED ? [] : $operation->parameters; + $operation->parameters = Generator::isDefault($operation->parameters) ? [] : $operation->parameters; foreach ($schema->properties as $property) { - $isNullable = $property->nullable !== Generator::UNDEFINED ? $property->nullable : false; + $isNullable = Generator::isDefault($property->nullable) ? false : $property->nullable; $schema = new Schema( - type: $property->format !== Generator::UNDEFINED ? $property->format : $property->type, + type: Generator::isDefault($property->format) ? $property->type : $property->format, nullable: $isNullable ); $schema->_context = $operation->_context; // inherit context from operation, required to pretend to be a parameter $parameter = new Parameter( name: $property->property, - description: $property->description !== Generator::UNDEFINED ? $property->description : null, + description: Generator::isDefault($property->description) ? null : $property->description, in: 'query', required: !$isNullable, schema: $schema, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3e34c3bca..bf3cd6107 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,24 +1,9 @@ parameters: ignoreErrors: - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 1 - path: Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php - - message: "#^Property OpenApi\\\\Annotations\\\\AbstractAnnotation\\:\\:\\$x \\(array\\\\) does not accept string\\.$#" count: 1 - path: Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php - - - - message: "#^Strict comparison using \\=\\=\\= between array\\ and '@OA\\\\\\\\Generator\\:…' will always evaluate to false\\.$#" - count: 1 - path: Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php - - - - message: "#^Strict comparison using \\=\\=\\= between array\\ and '@OA\\\\\\\\Generator\\:…' will always evaluate to false\\.$#" - count: 1 - path: Examples/processors/schema-query-parameter-attributes/SchemaQueryParameter.php + path: Examples/processors/schema-query-parameter/SchemaQueryParameter.php - message: "#^Result of && is always true\\.$#" From 1aa01aba5bc8baa7fddb6cd7abaf0a03caed123c Mon Sep 17 00:00:00 2001 From: DerManoMann Date: Mon, 15 Jul 2024 13:21:57 +1200 Subject: [PATCH 3/3] Update yaml --- .../schema-query-parameter/schema-query-parameter.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Examples/processors/schema-query-parameter/schema-query-parameter.yaml b/Examples/processors/schema-query-parameter/schema-query-parameter.yaml index 852a5708c..54ab19c6e 100644 --- a/Examples/processors/schema-query-parameter/schema-query-parameter.yaml +++ b/Examples/processors/schema-query-parameter/schema-query-parameter.yaml @@ -67,3 +67,7 @@ components: example: 'Lorem ipsum' nullable: true type: object +tags: + - + name: Products + description: Products