From 081a83ed99194537f50d90252b1b7639067c702e Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Jul 2021 13:09:15 +0200 Subject: [PATCH 01/11] Changes to allow php 7.4 --- composer.json | 2 +- .../Paths/Operation/RequestBodyBuilder.php | 2 +- .../Paths/Operation/ResponseBuilder.php | 2 +- .../Paths/Operation/SchemaBuilder.php | 72 ++++++++++----- src/Builders/Paths/OperationBuilder.php | 2 +- src/ComponentsContainer.php | 29 ++++-- .../ResolvesActionTraitToDescriptor.php | 2 +- .../Schema/PaginationDescriptor.php | 2 +- src/Descriptors/Actions/ActionDescriptor.php | 23 +++-- .../Responses/ResponseDescriptor.php | 2 +- src/Descriptors/Schema/Schema.php | 89 ++++++++++++------- src/Generator.php | 8 +- src/OpenApiGenerator.php | 3 +- src/ResourceContainer.php | 8 +- src/Route.php | 13 +-- 15 files changed, 169 insertions(+), 90 deletions(-) diff --git a/composer.json b/composer.json index e5edddd..1d68d9c 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ ], "license": "Apache-2.0", "require": { - "php": "^8.0", + "php": "^7.4", "laravel-json-api/hashids": "^1.0@beta", "goldspecdigital/oooas": "^2.8", "justinrainbow/json-schema": "^5.2" diff --git a/src/Builders/Paths/Operation/RequestBodyBuilder.php b/src/Builders/Paths/Operation/RequestBodyBuilder.php index 74e93be..614e16f 100644 --- a/src/Builders/Paths/Operation/RequestBodyBuilder.php +++ b/src/Builders/Paths/Operation/RequestBodyBuilder.php @@ -38,7 +38,7 @@ public function __construct( public function build(Route $route): ?RequestBody { - return $this->getDescriptor($route)?->request(); + return $this->getDescriptor($route) !== NULL ? $this->getDescriptor($route)->request() : NULL; } /** diff --git a/src/Builders/Paths/Operation/ResponseBuilder.php b/src/Builders/Paths/Operation/ResponseBuilder.php index f1a95ed..0d3833e 100644 --- a/src/Builders/Paths/Operation/ResponseBuilder.php +++ b/src/Builders/Paths/Operation/ResponseBuilder.php @@ -65,7 +65,7 @@ public function __construct( */ public function build(Route $route): array { - return $this->getDescriptor($route)?->response(); + return $this->getDescriptor($route)->response(); } /** diff --git a/src/Builders/Paths/Operation/SchemaBuilder.php b/src/Builders/Paths/Operation/SchemaBuilder.php index 52aca49..fe95b86 100644 --- a/src/Builders/Paths/Operation/SchemaBuilder.php +++ b/src/Builders/Paths/Operation/SchemaBuilder.php @@ -111,20 +111,28 @@ protected function buildResponseSchema( if ($method !== 'showRelated' && $route->isRelation()) { $schema = $descriptor->fetchRelationship($route); } else { - $schema = match ($method) { - 'index', 'show', 'store', 'update' => $descriptor->fetch( + switch ($method) { + case 'index': + case 'show': + case 'store': + case 'update': + $schema = $descriptor->fetch( $route->schema(), $objectId, $route->resource(), $route->name(true) - ), - 'showRelated' => $descriptor->fetch( + ); + break; + case 'showRelated': + $schema = $descriptor->fetch( $route->inversSchema(), $objectId, - $route->relation()?->inverse(), + $route->relation() !== null ? $route->relation()->inverse() : null, $route->inverseName(true) - ), - default => die($method) // @todo Add proper Exception + ); + break; + default: + die($method); // @todo Add proper Exception }; } @@ -147,17 +155,29 @@ protected function buildRequestSchema( $method = $route->action(); if ($route->isRelation()) { - $schema = match ($method) { - 'update' => $descriptor->updateRelationship($route), - 'attach' => $descriptor->attachRelationship($route), - 'detach' => $descriptor->detachRelationship($route), - default => die("Request ".$method) // @todo Add proper Exception - }; + switch ($method) { + case 'update': + $schema = $descriptor->updateRelationship($route); + break; + case 'attach': + $schema = $descriptor->attachRelationship($route); + break; + case 'detach': + $schema = $descriptor->detachRelationship($route); + break; + default: + die("Request ".$method); // @todo Add proper Exception + } } else { - $schema = match ($method) { - 'store' => $descriptor->store($route), - 'update' => $descriptor->update($route), - default => die("Request ".$method) // @todo Add proper Exception + switch ($method) { + case 'store': + $schema = $descriptor->store($route); + break; + case 'update': + $schema = $descriptor->update($route); + break; + default: + die("Request ".$method); // @todo Add proper Exception }; } @@ -181,12 +201,22 @@ public static function objectId( $resource = $route->resource(); } else { - $method = match ($route->action()) { - 'index', 'show', 'showRelated', 'store', 'update', 'attach', 'detach' => 'fetch', - default => $route->action() + switch ($route->action()) { + case 'index': + case 'show': + case 'showRelated': + case 'store': + case 'update': + case 'attach': + case 'detach': + $method = 'fetch'; + break; + default: + $method = $route->action(); }; - $resource = $route->action() === 'showRelated' ? $route->relation()?->inverse() : $route->resource(); + + $resource = $route->action() === 'showRelated' ? $route->relation()->inverse() : $route->resource(); } if ($route->isPolymorphic() && $route->action() === 'showRelated') { diff --git a/src/Builders/Paths/OperationBuilder.php b/src/Builders/Paths/OperationBuilder.php index 607a146..a99d49a 100644 --- a/src/Builders/Paths/OperationBuilder.php +++ b/src/Builders/Paths/OperationBuilder.php @@ -67,7 +67,7 @@ public function __construct( */ public function build(SpecRoute $route): ?Operation { - return $this->getDescriptor($route)?->action(); + return $this->getDescriptor($route) !== NULL ? $this->getDescriptor($route)->action() : NULL; } /** diff --git a/src/ComponentsContainer.php b/src/ComponentsContainer.php index f5bb262..74c45d1 100644 --- a/src/ComponentsContainer.php +++ b/src/ComponentsContainer.php @@ -96,7 +96,7 @@ public function components(): Components ->responses(...$this->responses) ->parameters(...$this->parameters) ->requestBodies(...$this->requestBodies) - ->schemas(...$schemas); + ->schemas(...array_values($schemas)); } /** @@ -107,16 +107,27 @@ public function components(): Components protected function ref(BaseObject $object): BaseObject { - $baseRef = match (true) { - $object instanceof Parameter => '#/components/parameters/', - $object instanceof RequestBody => '#/components/requestBodies/', - $object instanceof Response => '#/components/responses/', - $object instanceof SchemaContract => '#/components/schemas/', - $object instanceof SecurityScheme => '#/components/securitySchemes/', - default => die($object::class) + switch (true) { + case $object instanceof Parameter: + $baseRef = '#/components/parameters/'; + break; + case $object instanceof RequestBody: + $baseRef = '#/components/requestBodies/'; + break; + case $object instanceof Response: + $baseRef = '#/components/responses/'; + break; + case $object instanceof SchemaContract: + $baseRef = '#/components/schemas/'; + break; + case $object instanceof SecurityScheme: + $baseRef = '#/components/securitySchemes/'; + break; + default: + die(get_class($object)); }; - return $object::class::ref($baseRef.$object->objectId, + return $object::ref($baseRef.$object->objectId, $object->objectId); } diff --git a/src/Concerns/ResolvesActionTraitToDescriptor.php b/src/Concerns/ResolvesActionTraitToDescriptor.php index 352ccdc..1fac285 100644 --- a/src/Concerns/ResolvesActionTraitToDescriptor.php +++ b/src/Concerns/ResolvesActionTraitToDescriptor.php @@ -35,7 +35,7 @@ protected function descriptorClass(SpecRoute $route): ?string return null; } - return $traitMethod?->getDeclaringClass()->name; + return $traitMethod !== NULL ? $traitMethod->getDeclaringClass()->name : NULL; } } diff --git a/src/Contracts/Descriptors/Schema/PaginationDescriptor.php b/src/Contracts/Descriptors/Schema/PaginationDescriptor.php index 81ddba8..ceda3ef 100644 --- a/src/Contracts/Descriptors/Schema/PaginationDescriptor.php +++ b/src/Contracts/Descriptors/Schema/PaginationDescriptor.php @@ -15,5 +15,5 @@ interface PaginationDescriptor extends Descriptor * * @return mixed */ - public function pagination(Route $route): mixed; + public function pagination(Route $route); } diff --git a/src/Descriptors/Actions/ActionDescriptor.php b/src/Descriptors/Actions/ActionDescriptor.php index 9ea8273..6c8cd9e 100644 --- a/src/Descriptors/Actions/ActionDescriptor.php +++ b/src/Descriptors/Actions/ActionDescriptor.php @@ -33,7 +33,7 @@ public function __construct( RequestBodyBuilder $requestBodyBuilder, ResponseBuilder $responseBuilder, Generator $generator, - Route $route, + Route $route ) { $this->parameterBuilder = $parameterBuilder; $this->requestBodyBuilder = $requestBodyBuilder; @@ -49,12 +49,21 @@ public function __construct( */ public function action(): Operation { - $operation = match ($this->route->method()) { - 'GET' => Operation::get(), - 'POST' => Operation::post(), - 'PATCH' => Operation::patch(), - 'DELETE' => Operation::delete(), - }; + switch ($this->route->method()) { + case 'POST': + $operation = Operation::post(); + break; + case 'PATCH': + $operation = Operation::patch(); + break; + case 'DELETE': + $operation = Operation::delete(); + break; + case 'GET': + default: + $operation = Operation::get(); + break; + } return $operation ->operationId($this->route->id()) diff --git a/src/Descriptors/Responses/ResponseDescriptor.php b/src/Descriptors/Responses/ResponseDescriptor.php index 32d7a01..93c6248 100644 --- a/src/Descriptors/Responses/ResponseDescriptor.php +++ b/src/Descriptors/Responses/ResponseDescriptor.php @@ -37,7 +37,7 @@ public function __construct( Generator $generator, Route $route, SchemaBuilder $schemaBuilder, - Collection $defaults, + Collection $defaults ) { parent::__construct($generator); $this->route = $route; diff --git a/src/Descriptors/Schema/Schema.php b/src/Descriptors/Schema/Schema.php index 938e987..0083083 100644 --- a/src/Descriptors/Schema/Schema.php +++ b/src/Descriptors/Schema/Schema.php @@ -159,8 +159,9 @@ public function fetchRelationship(Route $route): OASchema ->resource(Arr::first($route->inversSchemas())::model()); } - return $this->relationshipData($route->relation(), $resource, - $route->relation()?->inverse()) + $inverseRelation = $route->relation() !== null ? $route->relation()->inverse() : null; + return $this->relationshipData($route->relation(), $resource, + $inverseRelation) ->title('Resource/'.ucfirst($route->name(true)).'/Relationship/'.ucfirst($route->relationName()).'/Fetch'); } @@ -178,8 +179,9 @@ public function updateRelationship(Route $route): OASchema ->resource(Arr::first($route->inversSchemas())::model()); } + $inverseRelation = $route->relation() !== null ? $route->relation()->inverse() : null; return $this->relationshipData($route->relation(), $resource, - $route->relation()?->inverse()) + $inverseRelation) ->title('Resource/'.ucfirst($route->name(true)).'/Relationship/'.ucfirst($route->relationName()).'/Update'); } @@ -197,8 +199,9 @@ public function attachRelationship(Route $route): OASchema ->resource(Arr::first($route->inversSchemas())::model()); } + $inverseRelation = $route->relation() !== null ? $route->relation()->inverse() : null; return $this->relationshipData($route->relation(), $resource, - $route->relation()?->inverse()) + $inverseRelation) ->title('Resource/'.ucfirst($route->name(true)).'/Relationship/'.ucfirst($route->relationName()).'/Attach'); } @@ -215,9 +218,9 @@ public function detachRelationship(Route $route): OASchema $resource = $this->generator->resources() ->resource(Arr::first($route->inversSchemas())::model()); } - + $inverseRelation = $route->relation() !== null ? $route->relation()->inverse() : null; return $this->relationshipData($route->relation(), $resource, - $route->relation()?->inverse()) + $inverseRelation) ->title('Resource/'.ucfirst($route->name(true)).'/Relationship/'.ucfirst($route->relationName()).'/Detach'); } @@ -231,8 +234,9 @@ public function fetchPolymorphicRelationship( $resource = $this->generator->resources() ->resource($route->schema()::model()); + $inverseRelation = $route->relation() !== null ? $route->relation()->inverse() : null; return $this->relationshipData($route->relation(), $resource, - $route->relation()?->inverse()) + $inverseRelation) ->objectId($objectId) ->title('Resource/'.ucfirst($route->name(true)).'/Relationship/'.ucfirst($route->relationName()).'/Fetch'); } @@ -323,8 +327,8 @@ public function filters($route): array return collect($route->schema()->filters()) ->map(function (Eloquent\Contracts\Filter $filterInstance) use ($route ) { - return (new ($this->getDescriptor($filterInstance))($this->generator, - $route, $filterInstance))->filter(); + $descriptor = $this->getDescriptor($filterInstance); + return (new $descriptor($this->generator, $route, $filterInstance))->filter(); }) ->flatten() ->toArray(); @@ -342,19 +346,27 @@ protected function fields( ): Collection { return collect($fields) ->mapToGroups(function (Field $field) { - $key = match (true) { - $field instanceof Attribute => 'attributes', - $field instanceof Relation => 'relationships', - default => 'unknown' - }; - return [$key => $field]; + switch (true) { + case $field instanceof Attribute: + $key = 'attributes'; + break; + case $field instanceof Relation: + $key = 'relationships'; + break; + default: + $key = 'unknown'; + } + return [$key => $field]; }) ->map(function ($fields, $type) use ($resource) { - return match ($type) { - 'attributes' => $this->attributes($fields, $resource), - 'relationships' => $this->relationships($fields, $resource), - default => null - }; + switch ($type) { + case 'attributes': + return $this->attributes($fields, $resource); + case 'relationships': + return $this->relationships($fields, $resource); + default: + return null; + } }); } @@ -369,14 +381,25 @@ protected function attributes( ->filter(fn($field) => ! ($field instanceof ID)) ->map(function (Field $field) use ($example) { $fieldId = $field->name(); - $schema = (match (true) { - $field instanceof Boolean => OASchema::boolean($fieldId), - $field instanceof Number => OASchema::number($fieldId), - $field instanceof ArrayList => OASchema::array($fieldId), - $field instanceof ArrayHash, - $field instanceof Map => OASchema::object($fieldId), - default => OASchema::string($fieldId) - })->title($field->name()); + switch (true) { + case $field instanceof Boolean: + $fieldDataType = OASchema::boolean($fieldId); + break; + case $field instanceof Number: + $fieldDataType = OASchema::number($fieldId); + break; + case $field instanceof ArrayList: + $fieldDataType = OASchema::array($fieldId); + break; + case $field instanceof ArrayHash: + case $field instanceof Map: + $fieldDataType = OASchema::object($fieldId); + break; + default: + $fieldDataType = OASchema::string($fieldId); + } + + $schema = $fieldDataType->title($field->name()); if (isset($example[$field->name()])) { $schema = $schema->example($example[$field->name()]); @@ -407,7 +430,7 @@ protected function relationships( } /** - * @param \LaravelJsonApi\Eloquent\Fields\Relations\Relation $relation + * @param \LaravelJsonApi\Eloquent\Fields\Relations\Relation $relation * @param \LaravelJsonApi\Core\Resources\JsonApiResource $example * @param bool $includeData * @@ -415,7 +438,7 @@ protected function relationships( * @throws \GoldSpecDigital\ObjectOrientedOAS\Exceptions\InvalidArgumentException */ protected function relationship( - mixed $relation, + Relation $relation, JsonApiResource $example, bool $includeData = false ): OASchema { @@ -442,7 +465,7 @@ protected function relationship( } /** - * @param \LaravelJsonApi\Eloquent\Fields\Relations\Relation $relation + * @param \LaravelJsonApi\Eloquent\Fields\Relations\Relation $relation * @param \LaravelJsonApi\Core\Resources\JsonApiResource $example * @param string $type * @@ -450,7 +473,7 @@ protected function relationship( * @throws \GoldSpecDigital\ObjectOrientedOAS\Exceptions\InvalidArgumentException */ protected function relationshipData( - mixed $relation, + Relation $relation, JsonApiResource $example, string $type ): OASchema { @@ -493,7 +516,7 @@ protected function relationshipData( * @return \GoldSpecDigital\ObjectOrientedOAS\Objects\Schema */ public function relationshipLinks( - mixed $relation, + $relation, JsonApiResource $example, string $type ): OASchema { diff --git a/src/Generator.php b/src/Generator.php index 60ce006..20b60c8 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -36,7 +36,11 @@ public function __construct($key) { $this->key = $key; - $this->server = new (config("jsonapi.servers.$key"))(app(), $this->key); + $apiServer = config("jsonapi.servers.$key"); + $app = app(); + + + $this->server = new $apiServer($app, $this->key); $this->infoBuilder = new InfoBuilder($this); $this->serverBuilder = new ServerBuilder($this); @@ -54,7 +58,7 @@ public function generate(): OpenApi ->openapi(OpenApi::OPENAPI_3_0_2) ->info($this->infoBuilder->build()) ->servers(...$this->serverBuilder->build()) - ->paths(...$this->pathsBuilder->build()) + ->paths(...array_values($this->pathsBuilder->build())) ->components($this->components()->components()); } diff --git a/src/OpenApiGenerator.php b/src/OpenApiGenerator.php index c2ec1a7..dfb4c47 100644 --- a/src/OpenApiGenerator.php +++ b/src/OpenApiGenerator.php @@ -14,7 +14,8 @@ class OpenApiGenerator public function generate(string $serverKey): string { - $openapi = (new Generator($serverKey))->generate(); + $generator = new Generator($serverKey); + $openapi = $generator->generate(); $openapi->validate(); diff --git a/src/ResourceContainer.php b/src/ResourceContainer.php index 1900ebc..accf999 100644 --- a/src/ResourceContainer.php +++ b/src/ResourceContainer.php @@ -26,7 +26,7 @@ public function __construct(Server $server) * * @return \LaravelJsonApi\Core\Resources\JsonApiResource */ - public function resource(mixed $model): JsonApiResource{ + public function resource($model): JsonApiResource{ $fqn = $this->getFQN($model); if(!isset($this->resource[$fqn])){ $this->loadResources($fqn); @@ -39,7 +39,7 @@ public function resource(mixed $model): JsonApiResource{ * * @return JsonApiResource[] */ - public function resources(mixed $model): array{ + public function resources($model): array{ $fqn = $this->getFQN($model); if(!isset($this->resource[$fqn])){ $this->loadResources($fqn); @@ -47,13 +47,13 @@ public function resources(mixed $model): array{ return $this->resources[$fqn]->toArray(); } - protected function getFQN(mixed $model): string{ + protected function getFQN($model): string{ $fqn = $model; if($model instanceof Schema){ $fqn = $model::model(); } else if(is_object($model)) { - $fqn = $model::class; + $fqn = get_class($model); } return $fqn; } diff --git a/src/Route.php b/src/Route.php index cf327d8..55a4800 100644 --- a/src/Route.php +++ b/src/Route.php @@ -194,7 +194,7 @@ public function isPolymorphic(): bool */ public function invers(): ?string { - return $this->relation()?->inverse(); + return $this->relation() !== null ? $this->relation()->inverse() : null; } /** @@ -207,7 +207,7 @@ public function inversSchema(): ?Schema throw new \LogicException("Method is not allowed for Polymorphic relationships"); } return $this->server->schemas() - ->schemaFor($this->relation()?->inverse()); + ->schemaFor($this->relation() !== null ? $this->relation()->inverse() : NULL); } return null; } @@ -241,10 +241,11 @@ public function inversSchemas(): array */ public function inverseName(bool $singular = false): ?string { - if ($singular) { - return Str::singular($this->relation()?->inverse()); - } - return $this->relation()?->inverse(); + $relation = $this->relation() !== NULL ? $this->relation()->inverse() : NULL; + if ($singular) { + return Str::singular($relation); + } + return $relation; } /** From c5a1ac4a44bdaf6d97e7cffef7a021b2ee0d69a8 Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Jul 2021 13:11:50 +0200 Subject: [PATCH 02/11] Fix base url call to url() --- src/Route.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Route.php b/src/Route.php index 55a4800..9b2198b 100644 --- a/src/Route.php +++ b/src/Route.php @@ -95,7 +95,7 @@ public function __construct(Server $server, IlluminateRoute $route) } $this->uri = str_replace( - $this->server->baseUri(), + $this->server->url(), '', '/'.$route->uri() ); From 424e91af976f9e4f60d6368f9b908190dd80756a Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Jul 2021 13:16:35 +0200 Subject: [PATCH 03/11] symfony yaml is needed for generation of spec file --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 1d68d9c..0c1507b 100644 --- a/composer.json +++ b/composer.json @@ -18,13 +18,13 @@ "php": "^7.4", "laravel-json-api/hashids": "^1.0@beta", "goldspecdigital/oooas": "^2.8", - "justinrainbow/json-schema": "^5.2" + "justinrainbow/json-schema": "^5.2", + "symfony/yaml": "^5.3" }, "require-dev": { "laravel-json-api/laravel": "^1.0", "orchestra/testbench": "^6.9", - "phpunit/phpunit": "^9.5", - "symfony/yaml": "^5.3@beta" + "phpunit/phpunit": "^9.5" }, "autoload": { "psr-4": { From 40145166a6d9404f02a96d7f4be492c17ab4e9bb Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Jul 2021 13:52:37 +0200 Subject: [PATCH 04/11] Limit examples to 3 since running this on a large database will result in very very large datasets --- src/Builders/Paths/Operation/ParameterBuilder.php | 2 +- src/Descriptors/Schema/Schema.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Builders/Paths/Operation/ParameterBuilder.php b/src/Builders/Paths/Operation/ParameterBuilder.php index 8e27227..67899fd 100644 --- a/src/Builders/Paths/Operation/ParameterBuilder.php +++ b/src/Builders/Paths/Operation/ParameterBuilder.php @@ -47,7 +47,7 @@ public function build(Route $route): array ->map(function ($resource) { $id = $resource->id(); return Example::create($id)->value($id); - })->toArray(); + })->take(3)->toArray(); $parameters[] = Parameter::path($id) ->name($id) diff --git a/src/Descriptors/Schema/Schema.php b/src/Descriptors/Schema/Schema.php index 0083083..15b24b2 100644 --- a/src/Descriptors/Schema/Schema.php +++ b/src/Descriptors/Schema/Schema.php @@ -408,7 +408,7 @@ protected function attributes( $schema = $schema->readOnly(true); } return $schema; - })->toArray(); + })->take(3)->toArray(); } /** From a3c591ce191aebf842bb8041cbeab65be953aef4 Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Jul 2021 16:45:40 +0200 Subject: [PATCH 05/11] Limit the examples. Limit was also limitting the fieldlist. --- src/Builders/Paths/Operation/ParameterBuilder.php | 2 +- src/Descriptors/Schema/Schema.php | 2 +- src/ResourceContainer.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Builders/Paths/Operation/ParameterBuilder.php b/src/Builders/Paths/Operation/ParameterBuilder.php index 67899fd..8e27227 100644 --- a/src/Builders/Paths/Operation/ParameterBuilder.php +++ b/src/Builders/Paths/Operation/ParameterBuilder.php @@ -47,7 +47,7 @@ public function build(Route $route): array ->map(function ($resource) { $id = $resource->id(); return Example::create($id)->value($id); - })->take(3)->toArray(); + })->toArray(); $parameters[] = Parameter::path($id) ->name($id) diff --git a/src/Descriptors/Schema/Schema.php b/src/Descriptors/Schema/Schema.php index 15b24b2..0083083 100644 --- a/src/Descriptors/Schema/Schema.php +++ b/src/Descriptors/Schema/Schema.php @@ -408,7 +408,7 @@ protected function attributes( $schema = $schema->readOnly(true); } return $schema; - })->take(3)->toArray(); + })->toArray(); } /** diff --git a/src/ResourceContainer.php b/src/ResourceContainer.php index accf999..0a45599 100644 --- a/src/ResourceContainer.php +++ b/src/ResourceContainer.php @@ -65,7 +65,7 @@ protected function loadResources(string $model){ if(method_exists($model, 'all')){ $resources = $model::all()->map(function ($model) { return $this->server->resources()->create($model); - }); + })->take(3); $this->resources[$model] = $resources; } From 2ed5367e6508dfe71bff413ed05fc1acd8178e0a Mon Sep 17 00:00:00 2001 From: bbrala Date: Mon, 2 Aug 2021 19:07:56 +0200 Subject: [PATCH 06/11] Update composer.json to allow php 7.4+ and php 8.x --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0c1507b..e61f4dc 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ ], "license": "Apache-2.0", "require": { - "php": "^7.4", + "php": ">=7.4|^8.0", "laravel-json-api/hashids": "^1.0@beta", "goldspecdigital/oooas": "^2.8", "justinrainbow/json-schema": "^5.2", From f6f571e82d0237d09bfc5d91d8a911b941b35af0 Mon Sep 17 00:00:00 2001 From: bbrala Date: Mon, 2 Aug 2021 19:09:56 +0200 Subject: [PATCH 07/11] Run tests on php 7.4 and php 8.0 --- .github/workflows/laravel.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/laravel.yml b/.github/workflows/laravel.yml index b824518..b88b703 100644 --- a/.github/workflows/laravel.yml +++ b/.github/workflows/laravel.yml @@ -9,11 +9,14 @@ on: jobs: laravel-tests: runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.4', '8.0'] steps: - uses: actions/checkout@v2 - uses: nanasess/setup-php@master with: - php-version: '8.0' + php-version: ${{ matrix.php }} - name: Install Dependencies run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist - name: Execute tests (Unit and Feature tests) via PHPUnit From 93d6b905d7479d9f76c24ded702f247054ecddb8 Mon Sep 17 00:00:00 2001 From: bjorn Date: Wed, 4 Aug 2021 16:06:51 +0200 Subject: [PATCH 08/11] Fix the path to the resources by removing the prefix. Added to test to check for correct paths. --- src/Route.php | 5 +++-- tests/Feature/GenerateTest.php | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Route.php b/src/Route.php index 9b2198b..a4a1629 100644 --- a/src/Route.php +++ b/src/Route.php @@ -94,10 +94,11 @@ public function __construct(Server $server, IlluminateRoute $route) $this->action = $action; } + $this->uri = str_replace( - $this->server->url(), + $route->getPrefix(), '', - '/'.$route->uri() + $route->uri() ); [$controller, $method] = explode('@', $this->route->getActionName(), 2); diff --git a/tests/Feature/GenerateTest.php b/tests/Feature/GenerateTest.php index cdc6dfa..6e6f01e 100644 --- a/tests/Feature/GenerateTest.php +++ b/tests/Feature/GenerateTest.php @@ -39,4 +39,17 @@ public function test_spec_file_generated() $this->assertEquals('My JSON:API', $spec['info']['title']); } + + public function test_url_is_properly_parsed() + { + GeneratorFacade::generate('v1'); + + $openapiYaml = GeneratorFacade::generate('v1'); + + $spec = Yaml::parse($openapiYaml); + + $this->assertArrayHasKey('/posts', $spec['paths'], 'Path to resource is not replaced correctly.'); + + $this->assertEquals('http://localhost/api/v1', $spec['servers'][0]['variables']['serverUrl']['default']); + } } From 27b1f27959444149ede8e6516a4a5e2d90f84334 Mon Sep 17 00:00:00 2001 From: bjorn Date: Mon, 26 Jul 2021 17:04:34 +0200 Subject: [PATCH 09/11] Allow generating json format --- src/Commands/GenerateCommand.php | 10 ++++++---- src/Facades/GeneratorFacade.php | 2 +- src/OpenApiGenerator.php | 17 ++++++++++------- tests/Feature/GenerateTest.php | 11 ++++++++++- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/Commands/GenerateCommand.php b/src/Commands/GenerateCommand.php index a121a3d..2bb5444 100644 --- a/src/Commands/GenerateCommand.php +++ b/src/Commands/GenerateCommand.php @@ -14,7 +14,8 @@ class GenerateCommand extends Command * * @var string */ - protected $signature = 'jsonapi:openapi:generate {serverKey}'; + protected $signature = 'jsonapi:openapi:generate {serverKey} {format=yaml}'; + /** * The console command description. @@ -31,10 +32,11 @@ class GenerateCommand extends Command public function handle() { $serverKey = $this->argument('serverKey'); + $format = $this->argument('format'); $this->info('Generating Open API spec...'); try { - GeneratorFacade::generate($serverKey); + GeneratorFacade::generate($serverKey, $format); } catch (ValidationException $exception) { $this->error('Validation failed'); $this->line('Errors:'); @@ -50,10 +52,10 @@ public function handle() return 1; } - $this->line('Complete! /storage/app/'.$serverKey.'_openapi.yaml'); + $this->line('Complete! /storage/app/'.$serverKey.'_openapi.' . $format); $this->newLine(); $this->line('Run the following to see your API docs'); - $this->info('speccy serve storage/app/'.$serverKey.'_openapi.yaml'); + $this->info('speccy serve storage/app/'.$serverKey.'_openapi.' . $format); $this->newLine(); return 0; diff --git a/src/Facades/GeneratorFacade.php b/src/Facades/GeneratorFacade.php index 3eec8ff..115b2e9 100644 --- a/src/Facades/GeneratorFacade.php +++ b/src/Facades/GeneratorFacade.php @@ -6,7 +6,7 @@ /** * Class GeneratorFacade - * @method static bool generate(string $serverKey) + * @method static bool generate(string $serverKey, string $format = 'yaml') */ class GeneratorFacade extends Facade { diff --git a/src/OpenApiGenerator.php b/src/OpenApiGenerator.php index dfb4c47..1f3fc68 100644 --- a/src/OpenApiGenerator.php +++ b/src/OpenApiGenerator.php @@ -11,20 +11,23 @@ class OpenApiGenerator /** * @throws \GoldSpecDigital\ObjectOrientedOAS\Exceptions\ValidationException */ - public function generate(string $serverKey): string + public function generate(string $serverKey, string $format = 'yaml'): string { $generator = new Generator($serverKey); $openapi = $generator->generate(); - $openapi->validate(); - - $yaml = Yaml::dump($openapi->toArray()); - + $openapi->validate(); + if ($format === 'yaml') { + $output = Yaml::dump($openapi->toArray()); // Save to storage - Storage::put($serverKey.'_openapi.yaml', $yaml); + Storage::put($serverKey.'_openapi.yaml', $output); + } elseif ($format === 'json') { + $output = json_encode($openapi->toArray(), JSON_PRETTY_PRINT); + Storage::put($serverKey.'_openapi.json', $output); + } - return $yaml; + return $output; } } diff --git a/tests/Feature/GenerateTest.php b/tests/Feature/GenerateTest.php index 6e6f01e..7570ceb 100644 --- a/tests/Feature/GenerateTest.php +++ b/tests/Feature/GenerateTest.php @@ -22,13 +22,22 @@ protected function setUp(): void public function test_spec_is_yaml() { - $openapiYaml = GeneratorFacade::generate('v1'); + $openapiYaml = GeneratorFacade::generate('v1', 'yaml'); $spec = Yaml::parse($openapiYaml); $this->assertEquals('My JSON:API', $spec['info']['title']); } + public function test_spec_is_json() + { + $output = GeneratorFacade::generate('v1', 'json'); + + $spec = json_decode($output); + + $this->assertEquals('My JSON:API', $spec['info']['title']); + } + public function test_spec_file_generated() { GeneratorFacade::generate('v1'); From 602d0373a2f88ed5240792623454a57a6d1fc4ff Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 5 Aug 2021 08:58:38 +0200 Subject: [PATCH 10/11] Fix json generate test. --- composer.json | 3 ++- tests/Feature/GenerateTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e61f4dc..49991d7 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "require-dev": { "laravel-json-api/laravel": "^1.0", "orchestra/testbench": "^6.9", - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^9.5", + "ext-json": "*" }, "autoload": { "psr-4": { diff --git a/tests/Feature/GenerateTest.php b/tests/Feature/GenerateTest.php index 7570ceb..1d91edb 100644 --- a/tests/Feature/GenerateTest.php +++ b/tests/Feature/GenerateTest.php @@ -33,7 +33,7 @@ public function test_spec_is_json() { $output = GeneratorFacade::generate('v1', 'json'); - $spec = json_decode($output); + $spec = json_decode($output, true); $this->assertEquals('My JSON:API', $spec['info']['title']); } From 3a9977d557e8b1d194d19219e367263136da4b21 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 5 Aug 2021 08:59:20 +0200 Subject: [PATCH 11/11] By default generate JSON instead of YAML --- src/Commands/GenerateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/GenerateCommand.php b/src/Commands/GenerateCommand.php index 2bb5444..d37d4dc 100644 --- a/src/Commands/GenerateCommand.php +++ b/src/Commands/GenerateCommand.php @@ -14,7 +14,7 @@ class GenerateCommand extends Command * * @var string */ - protected $signature = 'jsonapi:openapi:generate {serverKey} {format=yaml}'; + protected $signature = 'jsonapi:openapi:generate {serverKey} {format=json}'; /**