From acf33875aaff27aad657e5cbc1223290c51c8941 Mon Sep 17 00:00:00 2001 From: kukukk Date: Mon, 30 Sep 2024 18:57:10 +0300 Subject: [PATCH 1/5] Support Resource class --- src/Data/Property.php | 5 +++-- src/Data/Schema.php | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Data/Property.php b/src/Data/Property.php index 288e0f4..3887344 100644 --- a/src/Data/Property.php +++ b/src/Data/Property.php @@ -7,7 +7,7 @@ use ReflectionProperty; use RuntimeException; use Spatie\LaravelData\Data; -use Spatie\LaravelData\Data as LaravelData; +use Spatie\LaravelData\Support\Types\Storage\AcceptedTypesStorage; class Property extends Data { @@ -27,7 +27,8 @@ public function getName(): string */ public static function fromDataClass(string $class): Collection { - if (! is_a($class, LaravelData::class, true)) { + ['kind' => $kind] = AcceptedTypesStorage::getAcceptedTypesAndKind($class); + if ($kind->isNonDataRelated()) { throw new RuntimeException('Class does not extend LaravelData'); } diff --git a/src/Data/Schema.php b/src/Data/Schema.php index 2e070ec..0b4a71c 100644 --- a/src/Data/Schema.php +++ b/src/Data/Schema.php @@ -24,6 +24,7 @@ use Spatie\LaravelData\Support\Factories\DataPropertyFactory; use Spatie\LaravelData\Support\Transformation\TransformationContext; use Spatie\LaravelData\Support\Transformation\TransformationContextFactory; +use Spatie\LaravelData\Support\Types\Storage\AcceptedTypesStorage; use UnitEnum; use Xolvio\OpenApiGenerator\Attributes\CustomContentType; use Xolvio\OpenApiGenerator\Attributes\HttpResponseStatus; @@ -236,7 +237,8 @@ protected static function fromData(string $type_name, bool $nullable): self { $type_name = ltrim($type_name, '\\'); - if (! is_a($type_name, LaravelData::class, true)) { + ['kind' => $kind] = AcceptedTypesStorage::getAcceptedTypesAndKind($type_name); + if ($kind->isNonDataRelated()) { throw new RuntimeException("Type {$type_name} is not a Data class"); } @@ -259,7 +261,8 @@ protected static function fromDataCollection(string $type_name, bool $nullable): { $type_name = ltrim($type_name, '\\'); - if (! is_a($type_name, LaravelData::class, true)) { + ['kind' => $kind] = AcceptedTypesStorage::getAcceptedTypesAndKind($type_name); + if ($kind->isNonDataRelated()) { throw new RuntimeException("Type {$type_name} is not a Data class"); } From 0a012fa3802e84d8db7fb22ab1185b242ff5795a Mon Sep 17 00:00:00 2001 From: kukukk Date: Mon, 30 Sep 2024 18:57:30 +0300 Subject: [PATCH 2/5] Support single action controller --- src/Data/Operation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Data/Operation.php b/src/Data/Operation.php index 62b5ed4..7796a9c 100644 --- a/src/Data/Operation.php +++ b/src/Data/Operation.php @@ -7,6 +7,7 @@ use Illuminate\Http\Response as HttpResponse; use Illuminate\Routing\Route; use Illuminate\Support\Collection; +use Illuminate\Support\Str; use ReflectionClass; use ReflectionFunction; use ReflectionMethod; @@ -36,7 +37,7 @@ public static function fromRoute(Route $route, string $method): self if (is_string($uses)) { $controller_class = new ReflectionClass($route->getController()); - $controller_function = $controller_class->getMethod($route->getActionMethod()); + $controller_function = $controller_class->getMethod(Str::parseCallback($route->action['uses'])[1]); echo $controller_class->name, "::", $controller_function->name, "\n"; } elseif ($uses instanceof Closure) { From b2c987316a11c3a03a5b3830986a126bd15bf296 Mon Sep 17 00:00:00 2001 From: kukukk Date: Tue, 18 Mar 2025 14:06:57 +0200 Subject: [PATCH 3/5] Support Laravel 12 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 37ee0b9..48e91bc 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ }, "require": { "spatie/laravel-data": "^4", - "laravel/framework": "^8|^9|^10|^11", + "laravel/framework": "^8|^9|^10|^11|^12", "phpdocumentor/reflection-docblock": "^5.4", "spatie/invade": "^2" }, From 4299813cd55e6f68d64c2cbb75151c849b25f9b8 Mon Sep 17 00:00:00 2001 From: kukukk Date: Sat, 6 Dec 2025 22:48:22 +0200 Subject: [PATCH 4/5] Make routes availability configurable from env --- src/OpenApiServiceProvider.php | 4 ++++ src/config/openapi-generator.php | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/OpenApiServiceProvider.php b/src/OpenApiServiceProvider.php index 023e870..456d487 100644 --- a/src/OpenApiServiceProvider.php +++ b/src/OpenApiServiceProvider.php @@ -19,6 +19,10 @@ public function boot(): void ]); } + if (! config('openapi-generator.enabled')) { + return; + } + $this->loadRoutesFrom(__DIR__ . '/routes/routes.php'); $this->loadViewsFrom(__DIR__ . '/resources/views', 'openapi-generator'); } diff --git a/src/config/openapi-generator.php b/src/config/openapi-generator.php index 5cb4aeb..ba66871 100644 --- a/src/config/openapi-generator.php +++ b/src/config/openapi-generator.php @@ -1,6 +1,17 @@ env('OPENAPI_ENABLED', true), + /* |-------------------------------------------------------------------------- | OpenAPI version From 4396a7a1fdfb93f447789893cb0c147748b74dd1 Mon Sep 17 00:00:00 2001 From: kukukk Date: Tue, 3 Feb 2026 21:57:25 +0200 Subject: [PATCH 5/5] Support returning a Collection with class without FQN --- src/Data/Schema.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Data/Schema.php b/src/Data/Schema.php index 0b4a71c..cebbaa4 100644 --- a/src/Data/Schema.php +++ b/src/Data/Schema.php @@ -300,6 +300,29 @@ protected static function fromListDocblock(ReflectionMethod|ReflectionFunction|R } $class = $tag_type->getValueType()->__toString(); + if (! class_exists($class) && str_starts_with($class, '\\')) { + if ($reflection instanceof ReflectionProperty || $reflection instanceof ReflectionMethod) { + $declaringClass = $reflection->getDeclaringClass(); + } else { + throw new RuntimeException('Cannot resolve class from function reflection'); + } + + $fileName = $declaringClass->getFileName(); + if ($fileName) { + $fileContents = file_get_contents($fileName); + $className = ltrim($class, '\\'); + + // Match use statements + preg_match_all('/use\s+([^;]+);/i', $fileContents, $matches); + foreach ($matches[1] as $useStatement) { + $useStatement = trim($useStatement); + if (str_ends_with($useStatement, '\\' . $className) || $useStatement === $className) { + $class = '\\' . ltrim($useStatement, '\\'); + break; + } + } + } + } return new self( type: 'array',