From 561dac8003e37bdaeedb477f8d18e82121975f82 Mon Sep 17 00:00:00 2001 From: shalvah Date: Sat, 27 Aug 2022 20:10:29 +0200 Subject: [PATCH] Refactor --- CHANGELOG.md | 5 +- LICENSE.md | 2 +- README.md | 4 +- config/scribe.php | 2 +- src/Attributes/ResponseFromApiResource.php | 6 +- src/Attributes/ResponseFromFile.php | 4 +- src/Attributes/ResponseFromTransformer.php | 8 +- src/Attributes/Unauthenticated.php | 14 ++++ src/Commands/GenerateDocumentation.php | 6 +- src/Commands/Upgrade.php | 26 +++--- src/Extracting/InstantiatesExampleModels.php | 6 +- .../Strategies/Metadata/GetFromDocBlocks.php | 27 +++--- .../Metadata/GetFromMetadataAttributes.php | 2 + .../GetFromResponseFieldTag.php | 1 + .../Responses/UseResponseAttributes.php | 6 +- .../Responses/UseTransformerTags.php | 13 ++- .../TagStrategyWithFormRequestFallback.php | 2 +- .../GroupedEndpointsFromApp.php | 4 +- src/ScribeServiceProvider.php | 82 +++++++++++-------- .../GetFromMetadataAttributesTest.php | 31 +++++++ .../Responses/UseApiResourceTagsTest.php | 2 +- .../Responses/UseResponseAttributesTest.php | 4 +- 22 files changed, 161 insertions(+), 96 deletions(-) create mode 100644 src/Attributes/Unauthenticated.php diff --git a/CHANGELOG.md b/CHANGELOG.md index bfa442c..62ded1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,10 +18,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Support for specifying example model sources ([39ff208](https://github.com/knuckleswtf/scribe/commit/39ff208085d68eed4c459768ac5a1120934f021a)) - Support for subgroups ([7cf07738](https://github.com/knuckleswtf/scribe/commit/7cf0773864fbdd1772fea9a5ff9e7ffd3360d7d2),[2ebf40b](https://github.com/knuckleswtf/scribe/commit/2ebf40b5e5be309bf5e685a0cd58bb70856b033d)) - Nested response fields are now collapsed ([00b09bb](https://github.com/knuckleswtf/scribe/commit/00b09bbea8ec64006db864bf807004d48926c6d3)) -- Inlined routes (no more Scribe/Controller class) -- Changed signature of Strategy#invoke ($routeRules is now optional) +- `add_routes` now uses inline routes (no more `Scribe\Controller` class) +- Changed signature of Strategy ($routeRules is now optional,and there's now an instance var $endpointData, although it's not set by default) - Parameter data from successive stages is now merged - Basic support for overriding docs for inherited methods ([9735fdf](9735fdf150469f186bab395fcfabd042f570c50c)) +- note views may have changed ## 3.36.0 (12 August 2022) ### Modified diff --git a/LICENSE.md b/LICENSE.md index 48a4ed6..27a1b1f 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2021 Shalvah Adebayo +Copyright (c) 2022 Shalvah Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 35902b7..c237c6d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

-> [v3 is out now](https://scribe.knuckles.wtf/blog/2021/06/08/laravel-v3)! +> [v4 is out now](https://scribe.knuckles.wtf/blog/laravel-v4)! Scribe helps you generate API documentation for humans from your Laravel/Lumen/[Dingo](https://github.com/dingo/api) codebase. See a live example at [demo.scribe.knuckles.wtf](https://demo.scribe.knuckles.wtf). @@ -26,7 +26,7 @@ Scribe helps you generate API documentation for humans from your Laravel/Lumen/[ ## Documentation Check out the documentation at [scribe.knuckles.wtf/laravel](http://scribe.knuckles.wtf/laravel). -If you're coming from `mpociot/laravel-apidoc-generator`, there's a [migration guide](https://scribe.knuckles.wtf/laravel/migrating-apidoc). +If you're coming from `mpociot/laravel-apidoc-generator`, first [migrate to v3](http://scribe.knuckles.wtf/blog/laravel/3.x/migrating-apidoc)`, then [to v4](http://scribe.knuckles.wtf/blog/laravel/migrating-v4). ## Contributing Contributing is easy! See our [contribution guide](https://scribe.knuckles.wtf/laravel/contributing). diff --git a/config/scribe.php b/config/scribe.php index b7cabad..49e2956 100644 --- a/config/scribe.php +++ b/config/scribe.php @@ -358,7 +358,7 @@ INTRO * By default, Scribe will try the model's factory, and if that fails, try fetching the first from the database. * You can reorder or remove strategies here. */ - 'models_source' => ['factoryCreate', 'factoryMake', 'database'], + 'models_source' => ['factoryCreate', 'factoryMake', 'databaseFirst'], ], /** diff --git a/src/Attributes/ResponseFromApiResource.php b/src/Attributes/ResponseFromApiResource.php index cb8f27d..ba35824 100644 --- a/src/Attributes/ResponseFromApiResource.php +++ b/src/Attributes/ResponseFromApiResource.php @@ -11,16 +11,16 @@ class ResponseFromApiResource public string $name, public string $model, public int $status = 200, + public ?string $description = '', + /* Mark if this should be used as a collection. Only needed if not using a ResourceCollection. */ public bool $collection = false, - - public ?string $description = '', public array $factoryStates = [], public array $with = [], public ?int $paginate = null, public ?int $simplePaginate = null, - public array $additionalData = [], + public array $additional = [], ) { } diff --git a/src/Attributes/ResponseFromFile.php b/src/Attributes/ResponseFromFile.php index 42930f1..989f44c 100644 --- a/src/Attributes/ResponseFromFile.php +++ b/src/Attributes/ResponseFromFile.php @@ -9,9 +9,9 @@ use Knuckles\Scribe\Extracting\Shared\ResponseFileTools; class ResponseFromFile { public function __construct( - public ?string $file = null, + public string $file, public int $status = 200, - public array $merge = [], + public array|string $merge = [], public ?string $description = '', ) { } diff --git a/src/Attributes/ResponseFromTransformer.php b/src/Attributes/ResponseFromTransformer.php index d070a93..4c4a0e4 100644 --- a/src/Attributes/ResponseFromTransformer.php +++ b/src/Attributes/ResponseFromTransformer.php @@ -11,15 +11,15 @@ class ResponseFromTransformer public string $name, public string $model, public int $status = 200, - /* Mark if this should be used as a collection. */ - public bool $collection = false, - public ?string $description = '', + + /* Mark if this should be used as a collection. Only needed if not using a CollectionTransformer. */ + public bool $collection = false, public array $factoryStates = [], public array $with = [], public ?string $resourceKey = null, - /* Format: [numberPerPage, adapter]. Example: [10, SomePaginator::class] */ + /* Format: [adapter, numberPerPage]. Example: [SomePaginator::class, 10] */ public array $paginate = [], ) { } diff --git a/src/Attributes/Unauthenticated.php b/src/Attributes/Unauthenticated.php new file mode 100644 index 0000000..f0c5112 --- /dev/null +++ b/src/Attributes/Unauthenticated.php @@ -0,0 +1,14 @@ + false]; + } +} diff --git a/src/Commands/GenerateDocumentation.php b/src/Commands/GenerateDocumentation.php index 3ef6a71..054c52c 100644 --- a/src/Commands/GenerateDocumentation.php +++ b/src/Commands/GenerateDocumentation.php @@ -29,11 +29,11 @@ class GenerateDocumentation extends Command protected $description = 'Generate API documentation from your Laravel/Dingo routes.'; - private DocumentationConfig $docConfig; + protected DocumentationConfig $docConfig; - private bool $shouldExtract; + protected bool $shouldExtract; - private bool $forcing; + protected bool $forcing; protected string $configName; diff --git a/src/Commands/Upgrade.php b/src/Commands/Upgrade.php index 3cd5414..f2b37a7 100644 --- a/src/Commands/Upgrade.php +++ b/src/Commands/Upgrade.php @@ -3,6 +3,7 @@ namespace Knuckles\Scribe\Commands; use Illuminate\Console\Command; +use Knuckles\Scribe\Tools\Globals; use Shalvah\Upgrader\Upgrader; class Upgrade extends Command @@ -27,7 +28,9 @@ class Upgrade extends Command return; } - $this->info("Welcome to the Scribe v3 to v4 upgrader."); + $isMajorUpgrade = array_key_exists("default_group", $oldConfig) || array_key_exists("faker_seed", $oldConfig); + + $isMajorUpgrade && $this->info("Welcome to the Scribe v3 to v4 upgrader."); $this->line("Checking for config file changes..."); $upgrader = Upgrader::ofConfigFile("config/$configName.php", __DIR__ . '/../../config/scribe.php') @@ -53,6 +56,17 @@ class Upgrade extends Command } $this->newLine(); + if (!$isMajorUpgrade) { + $this->info("✔ Done."); + $this->info(sprintf("See the full changelog at https://github.com/knuckleswtf/scribe/blob/%s/CHANGELOG.md", Globals::SCRIBE_VERSION)); + return; + } + + $this->upgradeToV4(); + } + + protected function upgradeToV4(): void + { if ($this->confirm("Do you have any custom strategies?")) { $this->line('1. Add a new property public ?ExtractedEndpointData $endpointData;.'); $this->line('2. Replace the array $routeRules parameter in __invoke() with array $routeRules = [] .'); @@ -62,18 +76,10 @@ class Upgrade extends Command if ($this->confirm("Did you customize the Blade templates used by Scribe?")) { $this->warn('A few minor changes were made to the templates. See the release announcement for details.'); } - $this->newLine(); - - $this->line("Scribe now supports PHP 8 attributes for annotations. " - . "You can use both, but we recommend switching to attributes (see the docs)."); - if ($this->confirm("Would you like help in replacing your docblock tags with attributes?")) { - $this->warn('Install our Rector package knuckleswtf/scribe-rector-t2a and run it.'); - } - $this->warn("For attributes to work, you need to add the attribute strategies to your config file. See the release announcement for details."); $this->newLine(); $this->info("✔ Done."); - $this->line("See the release announcement at http://scribe.knuckles.wtf/v4 for the full upgrade guide!"); + $this->line("See the release announcement at http://scribe.knuckles.wtf/blog/laravel-v4 for the full upgrade guide!"); } } diff --git a/src/Extracting/InstantiatesExampleModels.php b/src/Extracting/InstantiatesExampleModels.php index 0e5a5f1..7543a75 100644 --- a/src/Extracting/InstantiatesExampleModels.php +++ b/src/Extracting/InstantiatesExampleModels.php @@ -18,12 +18,12 @@ trait InstantiatesExampleModels */ protected function instantiateExampleModel(string $type, array $factoryStates = [], array $relations = []) { - $configuredStrategies = $this->config->get('examples.models_source', ['factoryCreate', 'factoryMake', 'database']); + $configuredStrategies = $this->config->get('examples.models_source', ['factoryCreate', 'factoryMake', 'databaseFirst']); $strategies = [ 'factoryCreate' => fn() => $this->getExampleModelFromFactoryCreate($type, $factoryStates, $relations), 'factoryMake' => fn() => $this->getExampleModelFromFactoryMake($type, $factoryStates, $relations), - 'database' => fn() => $this->getExampleModelFromDatabase($type, $relations), + 'databaseFirst' => fn() => $this->getExampleModelFromDatabaseFirst($type, $relations), ]; foreach ($configuredStrategies as $strategyName) { @@ -51,7 +51,7 @@ trait InstantiatesExampleModels return $factory->make(); } - protected function getExampleModelFromDatabase(string $type, array $relations = []) + protected function getExampleModelFromDatabaseFirst(string $type, array $relations = []) { return $type::with($relations)->first(); } diff --git a/src/Extracting/Strategies/Metadata/GetFromDocBlocks.php b/src/Extracting/Strategies/Metadata/GetFromDocBlocks.php index dd21db2..67a85b1 100644 --- a/src/Extracting/Strategies/Metadata/GetFromDocBlocks.php +++ b/src/Extracting/Strategies/Metadata/GetFromDocBlocks.php @@ -60,42 +60,43 @@ class GetFromDocBlocks extends Strategy { foreach ($methodDocBlock->getTags() as $tag) { if ($tag->getName() === 'group') { - $routeGroupParts = explode("\n", trim($tag->getContent())); - $routeGroupName = array_shift($routeGroupParts); - $routeGroupDescription = trim(implode("\n", $routeGroupParts)); + $endpointGroupParts = explode("\n", trim($tag->getContent())); + $endpointGroupName = array_shift($endpointGroupParts); + $endpointGroupDescription = trim(implode("\n", $endpointGroupParts)); - // If the route has no title (the methodDocBlock's "short description"), - // we'll assume the routeGroupDescription is actually the title + // If the endpoint has no title (the methodDocBlock's "short description"), + // we'll assume the endpointGroupDescription is actually the title // Something like this: // /** - // * Fetch cars. <-- This is route title. + // * Fetch cars. <-- This is endpoint title. // * @group Cars <-- This is group name. // * APIs for cars. <-- This is group description (not required). // **/ // VS // /** // * @group Cars <-- This is group name. - // * Fetch cars. <-- This is route title, NOT group description. + // * Fetch cars. <-- This is endpoint title, NOT group description. // **/ // BTW, this is a spaghetti way of doing this. // It shall be refactored soon. Deus vult!💪 + // ...Or maybe not if (empty($methodDocBlock->getShortDescription())) { - return [$routeGroupName, '', $routeGroupDescription]; + return [$endpointGroupName, '', $endpointGroupDescription]; } - return [$routeGroupName, $routeGroupDescription, $methodDocBlock->getShortDescription()]; + return [$endpointGroupName, $endpointGroupDescription, $methodDocBlock->getShortDescription()]; } } // Fall back to the controller foreach ($controllerDocBlock->getTags() as $tag) { if ($tag->getName() === 'group') { - $routeGroupParts = explode("\n", trim($tag->getContent())); - $routeGroupName = array_shift($routeGroupParts); - $routeGroupDescription = implode("\n", $routeGroupParts); + $endpointGroupParts = explode("\n", trim($tag->getContent())); + $endpointGroupName = array_shift($endpointGroupParts); + $endpointGroupDescription = implode("\n", $endpointGroupParts); - return [$routeGroupName, $routeGroupDescription, $methodDocBlock->getShortDescription()]; + return [$endpointGroupName, $endpointGroupDescription, $methodDocBlock->getShortDescription()]; } } diff --git a/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php b/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php index f2637bf..3771549 100644 --- a/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php +++ b/src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php @@ -11,6 +11,7 @@ use Knuckles\Scribe\Attributes\ResponseFromApiResource; use Knuckles\Scribe\Attributes\ResponseFromFile; use Knuckles\Scribe\Attributes\ResponseFromTransformer; use Knuckles\Scribe\Attributes\Subgroup; +use Knuckles\Scribe\Attributes\Unauthenticated; use Knuckles\Scribe\Extracting\DatabaseTransactionHelpers; use Knuckles\Scribe\Extracting\InstantiatesExampleModels; use Knuckles\Scribe\Extracting\ParamHelpers; @@ -30,6 +31,7 @@ class GetFromMetadataAttributes extends PhpAttributeStrategy Subgroup::class, Endpoint::class, Authenticated::class, + Unauthenticated::class, ]; protected function extractFromAttributes( diff --git a/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldTag.php b/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldTag.php index c2e271b..697a8f9 100644 --- a/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldTag.php +++ b/src/Extracting/Strategies/ResponseFields/GetFromResponseFieldTag.php @@ -5,6 +5,7 @@ namespace Knuckles\Scribe\Extracting\Strategies\ResponseFields; use Knuckles\Scribe\Extracting\Shared\ResponseFieldTools; use Knuckles\Scribe\Extracting\Strategies\GetFieldsFromTagStrategy; use Mpociot\Reflection\DocBlock; +use Knuckles\Scribe\Tools\Utils as u; class GetFromResponseFieldTag extends GetFieldsFromTagStrategy { diff --git a/src/Extracting/Strategies/Responses/UseResponseAttributes.php b/src/Extracting/Strategies/Responses/UseResponseAttributes.php index c12a28d..09d16d6 100644 --- a/src/Extracting/Strategies/Responses/UseResponseAttributes.php +++ b/src/Extracting/Strategies/Responses/UseResponseAttributes.php @@ -61,7 +61,7 @@ class UseResponseAttributes extends PhpAttributeStrategy $this->startDbTransaction(); $content = ApiResourceResponseTools::fetch( $attributeInstance->name, $attributeInstance->collection, $modelInstantiator, - $this->endpointData, $pagination, $attributeInstance->additionalData, + $this->endpointData, $pagination, $attributeInstance->additional, ); $this->endDbTransaction(); @@ -76,7 +76,9 @@ class UseResponseAttributes extends PhpAttributeStrategy { $modelInstantiator = fn() => $this->instantiateExampleModel($attributeInstance->model, $attributeInstance->factoryStates, $attributeInstance->with); - $pagination = ['perPage' => $attributeInstance->paginate[0], 'adapter' => $attributeInstance->paginate[1]]; + $pagination = [ + 'perPage' => $attributeInstance->paginate[1] ?? null, 'adapter' => $attributeInstance->paginate[0] + ]; $this->startDbTransaction(); $content = TransformerResponseTools::fetch( $attributeInstance->name, $attributeInstance->collection, $modelInstantiator, diff --git a/src/Extracting/Strategies/Responses/UseTransformerTags.php b/src/Extracting/Strategies/Responses/UseTransformerTags.php index 9014b7e..697b581 100644 --- a/src/Extracting/Strategies/Responses/UseTransformerTags.php +++ b/src/Extracting/Strategies/Responses/UseTransformerTags.php @@ -4,7 +4,6 @@ namespace Knuckles\Scribe\Extracting\Strategies\Responses; use Knuckles\Camel\Extraction\ExtractedEndpointData; use Exception; -use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Arr; use Knuckles\Scribe\Extracting\DatabaseTransactionHelpers; use Knuckles\Scribe\Extracting\InstantiatesExampleModels; @@ -12,12 +11,7 @@ use Knuckles\Scribe\Extracting\RouteDocBlocker; use Knuckles\Scribe\Extracting\Shared\TransformerResponseTools; use Knuckles\Scribe\Extracting\Strategies\Strategy; use Knuckles\Scribe\Tools\AnnotationParser as a; -use Knuckles\Scribe\Tools\ConsoleOutputUtils as c; -use Knuckles\Scribe\Tools\ErrorHandlingUtils as e; use Knuckles\Scribe\Tools\Utils; -use League\Fractal\Manager; -use League\Fractal\Resource\Collection; -use League\Fractal\Resource\Item; use Mpociot\Reflection\DocBlock\Tag; use ReflectionClass; use ReflectionFunctionAbstract; @@ -132,11 +126,14 @@ class UseTransformerTags extends Strategy return ['adapter' => null, 'perPage' => null]; } - preg_match('/^\s*(.+?)\s+(\d+)?$/', $tag->getContent(), $result); + preg_match('/^\s*(.+?)(\s+\d+)?$/', $tag->getContent(), $result); $paginatorAdapter = $result[1]; $perPage = $result[2] ?? null; + if ($perPage) { + $perPage = trim($perPage); + } - return ['adapter' => $paginatorAdapter, 'perPage' => $perPage]; + return ['adapter' => $paginatorAdapter, 'perPage' => $perPage ?: null]; } public function getTransformerResponseFromTags(array $tags): ?array diff --git a/src/Extracting/Strategies/TagStrategyWithFormRequestFallback.php b/src/Extracting/Strategies/TagStrategyWithFormRequestFallback.php index f2e0c62..eb2c075 100644 --- a/src/Extracting/Strategies/TagStrategyWithFormRequestFallback.php +++ b/src/Extracting/Strategies/TagStrategyWithFormRequestFallback.php @@ -22,7 +22,7 @@ abstract class TagStrategyWithFormRequestFallback extends Strategy public function getParametersFromDocBlockInFormRequestOrMethod(Route $route, ReflectionFunctionAbstract $method): array { $classTags = RouteDocBlocker::getDocBlocksFromRoute($route)['class']?->getTags() ?: []; - // If there's a FormRequest, we check there for tags. + // If there's a FormRequest, w.e check there for tags. if ($formRequestClass = $this->getFormRequestReflectionClass($method)) { $formRequestDocBlock = new DocBlock($formRequestClass->getDocComment()); $parametersFromFormRequest = $this->getFromTags($formRequestDocBlock->getTags(), $classTags); diff --git a/src/GroupedEndpoints/GroupedEndpointsFromApp.php b/src/GroupedEndpoints/GroupedEndpointsFromApp.php index d8a9da7..052d39c 100644 --- a/src/GroupedEndpoints/GroupedEndpointsFromApp.php +++ b/src/GroupedEndpoints/GroupedEndpointsFromApp.php @@ -95,7 +95,7 @@ class GroupedEndpointsFromApp implements GroupedEndpointsContract */ private function extractEndpointsInfoFromLaravelApp(array $matches, array $cachedEndpoints, array $latestEndpointsData, array $groups): array { - $generator = $this->makeExtractor(); + $extractor = $this->makeExtractor(); $parsedEndpoints = []; @@ -120,7 +120,7 @@ class GroupedEndpointsFromApp implements GroupedEndpointsContract try { c::info('Processing route: ' . c::getRouteRepresentation($route)); - $currentEndpointData = $generator->processRoute($route, $routeItem->getRules()); + $currentEndpointData = $extractor->processRoute($route, $routeItem->getRules()); // If latest data is different from cached data, merge latest into current [$currentEndpointData, $index] = $this->mergeAnyEndpointDataUpdates($currentEndpointData, $cachedEndpoints, $latestEndpointsData, $groups); diff --git a/src/ScribeServiceProvider.php b/src/ScribeServiceProvider.php index 0b868a7..6e94951 100644 --- a/src/ScribeServiceProvider.php +++ b/src/ScribeServiceProvider.php @@ -13,48 +13,15 @@ use Knuckles\Scribe\Tools\Utils; class ScribeServiceProvider extends ServiceProvider { - /** - * Bootstrap the application events. - * - * @return void - */ public function boot() { - // Register custom Markdown Blade compiler so we can automatically have MD views converted to HTML - $this->app->view->getEngineResolver() - ->register('blademd', fn() => new BladeMarkdownEngine($this->app['blade.compiler'])); - $this->app->view->addExtension('md.blade.php', 'blademd'); + $this->registerViews(); - $this->loadViewsFrom(__DIR__ . '/../resources/views/', 'scribe'); - - // Publish views in separate, smaller groups for ease of end-user modifications - $viewGroups = [ - 'views' => '', - 'examples' => 'partials/example-requests', - 'themes' => 'themes', - 'markdown' => 'markdown', - ]; - foreach ($viewGroups as $group => $path) { - $this->publishes([ - __DIR__ . "/../resources/views/$path" => $this->app->basePath("resources/views/vendor/scribe/$path"), - ], "scribe-$group"); - } - - $this->publishes([ - __DIR__ . '/../config/scribe.php' => $this->app->configPath('scribe.php'), - ], 'scribe-config'); - - $this->mergeConfigFrom(__DIR__ . '/../config/scribe.php', 'scribe'); + $this->registerConfig(); $this->bootRoutes(); - if ($this->app->runningInConsole()) { - $this->commands([ - GenerateDocumentation::class, - MakeStrategy::class, - Upgrade::class, - ]); - } + $this->registerCommands(); // Bind the route matcher implementation $this->app->bind(RouteMatcherInterface::class, config('scribe.routeMatcher', RouteMatcher::class)); @@ -78,4 +45,47 @@ class ScribeServiceProvider extends ServiceProvider $this->loadRoutesFrom($routesPath); } } + + protected function registerViews(): void + { + // Register custom Markdown Blade compiler so we can automatically have MD views converted to HTML + $this->app->view->getEngineResolver() + ->register('blademd', fn() => new BladeMarkdownEngine($this->app['blade.compiler'])); + $this->app->view->addExtension('md.blade.php', 'blademd'); + + $this->loadViewsFrom(__DIR__ . '/../resources/views/', 'scribe'); + + // Publish views in separate, smaller groups for ease of end-user modifications + $viewGroups = [ + 'views' => '', + 'examples' => 'partials/example-requests', + 'themes' => 'themes', + 'markdown' => 'markdown', + ]; + foreach ($viewGroups as $group => $path) { + $this->publishes([ + __DIR__ . "/../resources/views/$path" => $this->app->basePath("resources/views/vendor/scribe/$path"), + ], "scribe-$group"); + } + } + + protected function registerConfig(): void + { + $this->publishes([ + __DIR__ . '/../config/scribe.php' => $this->app->configPath('scribe.php'), + ], 'scribe-config'); + + $this->mergeConfigFrom(__DIR__ . '/../config/scribe.php', 'scribe'); + } + + protected function registerCommands(): void + { + if ($this->app->runningInConsole()) { + $this->commands([ + GenerateDocumentation::class, + MakeStrategy::class, + Upgrade::class, + ]); + } + } } diff --git a/tests/Strategies/Metadata/GetFromMetadataAttributesTest.php b/tests/Strategies/Metadata/GetFromMetadataAttributesTest.php index 8a22ed3..3ed9b38 100644 --- a/tests/Strategies/Metadata/GetFromMetadataAttributesTest.php +++ b/tests/Strategies/Metadata/GetFromMetadataAttributesTest.php @@ -8,6 +8,7 @@ use Knuckles\Scribe\Attributes\Authenticated; use Knuckles\Scribe\Attributes\Endpoint; use Knuckles\Scribe\Attributes\Group; use Knuckles\Scribe\Attributes\Subgroup; +use Knuckles\Scribe\Attributes\Unauthenticated; use Knuckles\Scribe\Extracting\Strategies\Metadata\GetFromMetadataAttributes; use Knuckles\Scribe\Tools\DocumentationConfig; use PHPUnit\Framework\TestCase; @@ -81,6 +82,23 @@ class UseMetadataAttributesTest extends TestCase "description" => "", "authenticated" => false, ], $results); + + $endpoint = $this->endpoint(function (ExtractedEndpointData $e) { + $e->controller = new ReflectionClass(MetadataAttributesTestController2::class); + $e->method = $e->controller->getMethod('c1'); + }); + $results = $this->fetch($endpoint); + $this->assertArraySubset([ + "authenticated" => true, + ], $results); + $endpoint = $this->endpoint(function (ExtractedEndpointData $e) { + $e->controller = new ReflectionClass(MetadataAttributesTestController2::class); + $e->method = $e->controller->getMethod('c2'); + }); + $results = $this->fetch($endpoint); + $this->assertArraySubset([ + "authenticated" => false, + ], $results); } protected function fetch($endpoint): array @@ -132,3 +150,16 @@ class MetadataAttributesTestController { } } + +#[Authenticated] +class MetadataAttributesTestController2 +{ + public function c1() + { + } + + #[Unauthenticated] + public function c2() + { + } +} diff --git a/tests/Strategies/Responses/UseApiResourceTagsTest.php b/tests/Strategies/Responses/UseApiResourceTagsTest.php index 5e6d2ef..8ef6c94 100644 --- a/tests/Strategies/Responses/UseApiResourceTagsTest.php +++ b/tests/Strategies/Responses/UseApiResourceTagsTest.php @@ -92,7 +92,7 @@ class UseApiResourceTagsTest extends BaseLaravelTest /** @test */ public function respects_models_source_settings() { - $config = new DocumentationConfig(['examples' => ['models_source' => ['database', 'factoryMake']]]); + $config = new DocumentationConfig(['examples' => ['models_source' => ['databaseFirst', 'factoryMake']]]); $route = new Route(['POST'], "/somethingRandom", ['uses' => [TestController::class, 'dummy']]); $strategy = new UseApiResourceTags($config); diff --git a/tests/Strategies/Responses/UseResponseAttributesTest.php b/tests/Strategies/Responses/UseResponseAttributesTest.php index 5c80d1f..aea687e 100644 --- a/tests/Strategies/Responses/UseResponseAttributesTest.php +++ b/tests/Strategies/Responses/UseResponseAttributesTest.php @@ -211,14 +211,14 @@ class ResponseAttributesTestController } #[ResponseFromApiResource(TestUserApiResource::class, TestUser::class, collection: true, - factoryStates: ["state1", "random-state"], simplePaginate: 1, additionalData: ["a" => "b"])] + factoryStates: ["state1", "random-state"], simplePaginate: 1, additional: ["a" => "b"])] public function apiResourceAttributes() { } #[ResponseFromTransformer(TestTransformer::class, TestModel::class, collection: true, - paginate: [1, IlluminatePaginatorAdapter::class])] + paginate: [IlluminatePaginatorAdapter::class, 1])] public function transformerAttributes() {