diff --git a/src/Extracting/Strategies/BodyParameters/GetFromBodyParamAttribute.php b/src/Extracting/Strategies/BodyParameters/GetFromBodyParamAttribute.php index fe905fb6..2254553f 100644 --- a/src/Extracting/Strategies/BodyParameters/GetFromBodyParamAttribute.php +++ b/src/Extracting/Strategies/BodyParameters/GetFromBodyParamAttribute.php @@ -10,5 +10,5 @@ */ class GetFromBodyParamAttribute extends GetParamsFromAttributeStrategy { - protected array $attributeNames = [BodyParam::class]; + protected static array $attributeNames = [BodyParam::class]; } diff --git a/src/Extracting/Strategies/Headers/GetFromHeaderAttribute.php b/src/Extracting/Strategies/Headers/GetFromHeaderAttribute.php index de8f3d2e..3d7d903e 100644 --- a/src/Extracting/Strategies/Headers/GetFromHeaderAttribute.php +++ b/src/Extracting/Strategies/Headers/GetFromHeaderAttribute.php @@ -11,7 +11,7 @@ */ class GetFromHeaderAttribute extends PhpAttributeStrategy { - protected array $attributeNames = [Header::class]; + protected static array $attributeNames = [Header::class]; protected function extractFromAttributes( array $attributesOnMethod, array $attributesOnController, diff --git a/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php b/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php index 6a39f169..456de76a 100644 --- a/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php +++ b/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php @@ -18,7 +18,7 @@ class GetFromMetadataAttributes extends PhpAttributeStrategy { use ParamHelpers; - protected array $attributeNames = [ + protected static array $attributeNames = [ Group::class, Subgroup::class, Endpoint::class, diff --git a/src/Extracting/Strategies/PhpAttributeStrategy.php b/src/Extracting/Strategies/PhpAttributeStrategy.php index 450f0e17..1972fd10 100644 --- a/src/Extracting/Strategies/PhpAttributeStrategy.php +++ b/src/Extracting/Strategies/PhpAttributeStrategy.php @@ -18,7 +18,7 @@ abstract class PhpAttributeStrategy extends Strategy /** * @var string[] */ - protected array $attributeNames; + protected static array $attributeNames; public function __invoke(ExtractedEndpointData $endpointData, array $routeRules = []): array { @@ -37,12 +37,12 @@ public function __invoke(ExtractedEndpointData $endpointData, array $routeRules */ protected function getAttributes(ReflectionFunctionAbstract $method, ?ReflectionClass $class = null): array { - $attributesOnMethod = collect($this->attributeNames) + $attributesOnMethod = collect(static::$attributeNames) ->flatMap(fn(string $name) => $method->getAttributes($name)) ->map(fn(ReflectionAttribute $a) => $a->newInstance())->all(); if ($class) { - $attributesOnController = collect($this->attributeNames) + $attributesOnController = collect(static::$attributeNames) ->flatMap(fn(string $name) => $class->getAttributes($name)) ->map(fn(ReflectionAttribute $a) => $a->newInstance())->all(); } diff --git a/src/Extracting/Strategies/QueryParameters/GetFromQueryParamAttribute.php b/src/Extracting/Strategies/QueryParameters/GetFromQueryParamAttribute.php index 07dcf73b..c4e96901 100644 --- a/src/Extracting/Strategies/QueryParameters/GetFromQueryParamAttribute.php +++ b/src/Extracting/Strategies/QueryParameters/GetFromQueryParamAttribute.php @@ -10,5 +10,5 @@ */ class GetFromQueryParamAttribute extends GetParamsFromAttributeStrategy { - protected array $attributeNames = [QueryParam::class]; + protected static array $attributeNames = [QueryParam::class]; } diff --git a/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldAttribute.php b/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldAttribute.php index 3eef5543..9adf8223 100644 --- a/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldAttribute.php +++ b/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldAttribute.php @@ -4,22 +4,39 @@ use Knuckles\Camel\Extraction\ExtractedEndpointData; use Knuckles\Scribe\Attributes\ResponseField; +use Knuckles\Scribe\Attributes\ResponseFromApiResource; use Knuckles\Scribe\Extracting\Shared\ResponseFieldTools; use Knuckles\Scribe\Extracting\Strategies\PhpAttributeStrategy; +use Knuckles\Scribe\Tools\Utils as u; +use ReflectionAttribute; /** * @extends PhpAttributeStrategy */ class GetFromResponseFieldAttribute extends PhpAttributeStrategy { - protected array $attributeNames = [ResponseField::class]; + protected static array $attributeNames = [ResponseField::class]; protected function extractFromAttributes( array $attributesOnMethod, array $attributesOnController, ExtractedEndpointData $endpointData ): ?array { - return collect([...$attributesOnController, ...$attributesOnMethod]) + $attributesOnApiResourceMethods = []; + $apiResourceAttributes = $endpointData->method->getAttributes(ResponseFromApiResource::class); + + if (!empty($apiResourceAttributes)) { + $attributesOnApiResourceMethods = collect($apiResourceAttributes) + ->flatMap(function (ReflectionAttribute $attribute) { + $className = $attribute->newInstance()->name; + $method = u::getReflectedRouteMethod([$className, 'toArray']); + return collect($method->getAttributes(ResponseField::class)) + ->map(fn (ReflectionAttribute $attr) => $attr->newInstance()); + }); + } + + + return collect([...$attributesOnController, ...$attributesOnMethod, ...$attributesOnApiResourceMethods]) ->mapWithKeys(function ($attributeInstance) use ($endpointData) { $data = $attributeInstance->toArray(); diff --git a/src/Extracting/Strategies/Responses/UseResponseAttributes.php b/src/Extracting/Strategies/Responses/UseResponseAttributes.php index a7ab37a4..daee8de9 100644 --- a/src/Extracting/Strategies/Responses/UseResponseAttributes.php +++ b/src/Extracting/Strategies/Responses/UseResponseAttributes.php @@ -22,7 +22,7 @@ class UseResponseAttributes extends PhpAttributeStrategy { use ParamHelpers, DatabaseTransactionHelpers, InstantiatesExampleModels; - protected array $attributeNames = [ + protected static array $attributeNames = [ Response::class, ResponseFromFile::class, ResponseFromApiResource::class, diff --git a/src/Extracting/Strategies/UrlParameters/GetFromUrlParamAttribute.php b/src/Extracting/Strategies/UrlParameters/GetFromUrlParamAttribute.php index 69bd76e7..bdc685d1 100644 --- a/src/Extracting/Strategies/UrlParameters/GetFromUrlParamAttribute.php +++ b/src/Extracting/Strategies/UrlParameters/GetFromUrlParamAttribute.php @@ -10,5 +10,5 @@ */ class GetFromUrlParamAttribute extends GetParamsFromAttributeStrategy { - protected array $attributeNames = [UrlParam::class]; + protected static array $attributeNames = [UrlParam::class]; } diff --git a/tests/Fixtures/TestPetApiResource.php b/tests/Fixtures/TestPetApiResource.php index ef6e85ec..51b3bdfd 100644 --- a/tests/Fixtures/TestPetApiResource.php +++ b/tests/Fixtures/TestPetApiResource.php @@ -3,6 +3,7 @@ namespace Knuckles\Scribe\Tests\Fixtures; use Illuminate\Http\Resources\Json\JsonResource; +use Knuckles\Scribe\Attributes\ResponseField; class TestPetApiResource extends JsonResource { @@ -13,6 +14,8 @@ class TestPetApiResource extends JsonResource * * @return array */ + #[ResponseField('id', description: 'The id of the pet.')] + #[ResponseField('species', 'string', 'The breed')] public function toArray($request) { $result = [ diff --git a/tests/Strategies/ResponseFields/GetFromResponseFieldAttributesTest.php b/tests/Strategies/ResponseFields/GetFromResponseFieldAttributesTest.php index 73393466..490e8936 100644 --- a/tests/Strategies/ResponseFields/GetFromResponseFieldAttributesTest.php +++ b/tests/Strategies/ResponseFields/GetFromResponseFieldAttributesTest.php @@ -6,7 +6,10 @@ use Knuckles\Camel\Extraction\ExtractedEndpointData; use Knuckles\Camel\Extraction\ResponseCollection; use Knuckles\Scribe\Attributes\ResponseField; +use Knuckles\Scribe\Attributes\ResponseFromApiResource; use Knuckles\Scribe\Extracting\Strategies\ResponseFields\GetFromResponseFieldAttribute; +use Knuckles\Scribe\Tests\Fixtures\TestPet; +use Knuckles\Scribe\Tests\Fixtures\TestPetApiResource; use Knuckles\Scribe\Tools\DocumentationConfig; use PHPUnit\Framework\TestCase; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; @@ -51,6 +54,28 @@ public function can_fetch_from_responsefield_attribute() ], $results); } + /** @test */ + public function can_read_from_toArray_on_API_resources() + { + $endpoint = $this->endpoint(function (ExtractedEndpointData $e) { + $e->controller = new ReflectionClass(ResponseFieldAttributeTestController::class); + $e->method = $e->controller->getMethod('methodWithApiResourceResponse'); + $e->responses = new ResponseCollection([]); + }); + $results = $this->fetch($endpoint); + + $this->assertArraySubset([ + 'id' => [ + 'type' => '', + 'description' => 'The id of the pet.', + ], + 'species' => [ + 'type' => 'string', + 'description' => 'The breed', + ], + ], $results); + } + protected function fetch($endpoint): array { $strategy = new GetFromResponseFieldAttribute(new DocumentationConfig([])); @@ -76,4 +101,9 @@ class ResponseFieldAttributeTestController public function methodWithAttributes() { } + + #[ResponseFromApiResource(TestPetApiResource::class, TestPet::class)] + public function methodWithApiResourceResponse() + { + } }