Skip to content

Commit 561dac8

Browse files
committed
Refactor
1 parent 1f1f972 commit 561dac8

22 files changed

+153
-88
lines changed

CHANGELOG.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1818
- Support for specifying example model sources ([39ff208](https://github.com/knuckleswtf/scribe/commit/39ff208085d68eed4c459768ac5a1120934f021a))
1919
- Support for subgroups ([7cf07738](https://github.com/knuckleswtf/scribe/commit/7cf0773864fbdd1772fea9a5ff9e7ffd3360d7d2),[2ebf40b](https://github.com/knuckleswtf/scribe/commit/2ebf40b5e5be309bf5e685a0cd58bb70856b033d))
2020
- Nested response fields are now collapsed ([00b09bb](https://github.com/knuckleswtf/scribe/commit/00b09bbea8ec64006db864bf807004d48926c6d3))
21-
- Inlined routes (no more Scribe/Controller class)
22-
- Changed signature of Strategy#invoke ($routeRules is now optional)
21+
- `add_routes` now uses inline routes (no more `Scribe\Controller` class)
22+
- Changed signature of Strategy ($routeRules is now optional,and there's now an instance var $endpointData, although it's not set by default)
2323
- Parameter data from successive stages is now merged
2424
- Basic support for overriding docs for inherited methods ([9735fdf](9735fdf150469f186bab395fcfabd042f570c50c))
25+
- note views may have changed
2526

2627
## 3.36.0 (12 August 2022)
2728
### Modified

LICENSE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2021 Shalvah Adebayo
3+
Copyright (c) 2022 Shalvah
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</p>
88

99

10-
> [v3 is out now](https://scribe.knuckles.wtf/blog/2021/06/08/laravel-v3)!
10+
> [v4 is out now](https://scribe.knuckles.wtf/blog/laravel-v4)!
1111
1212
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).
1313

@@ -26,7 +26,7 @@ Scribe helps you generate API documentation for humans from your Laravel/Lumen/[
2626
## Documentation
2727
Check out the documentation at [scribe.knuckles.wtf/laravel](http://scribe.knuckles.wtf/laravel).
2828

29-
If you're coming from `mpociot/laravel-apidoc-generator`, there's a [migration guide](https://scribe.knuckles.wtf/laravel/migrating-apidoc).
29+
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).
3030

3131
## Contributing
3232
Contributing is easy! See our [contribution guide](https://scribe.knuckles.wtf/laravel/contributing).

config/scribe.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@
358358
* By default, Scribe will try the model's factory, and if that fails, try fetching the first from the database.
359359
* You can reorder or remove strategies here.
360360
*/
361-
'models_source' => ['factoryCreate', 'factoryMake', 'database'],
361+
'models_source' => ['factoryCreate', 'factoryMake', 'databaseFirst'],
362362
],
363363

364364
/**

src/Attributes/ResponseFromApiResource.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ public function __construct(
1111
public string $name,
1212
public string $model,
1313
public int $status = 200,
14+
public ?string $description = '',
15+
1416
/* Mark if this should be used as a collection. Only needed if not using a ResourceCollection. */
1517
public bool $collection = false,
16-
17-
public ?string $description = '',
1818
public array $factoryStates = [],
1919
public array $with = [],
2020

2121
public ?int $paginate = null,
2222
public ?int $simplePaginate = null,
23-
public array $additionalData = [],
23+
public array $additional = [],
2424
)
2525
{
2626
}

src/Attributes/ResponseFromFile.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
class ResponseFromFile
1010
{
1111
public function __construct(
12-
public ?string $file = null,
12+
public string $file,
1313
public int $status = 200,
14-
public array $merge = [],
14+
public array|string $merge = [],
1515
public ?string $description = '',
1616
) {
1717
}

src/Attributes/ResponseFromTransformer.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ public function __construct(
1111
public string $name,
1212
public string $model,
1313
public int $status = 200,
14-
/* Mark if this should be used as a collection. */
15-
public bool $collection = false,
16-
1714
public ?string $description = '',
15+
16+
/* Mark if this should be used as a collection. Only needed if not using a CollectionTransformer. */
17+
public bool $collection = false,
1818
public array $factoryStates = [],
1919
public array $with = [],
2020
public ?string $resourceKey = null,
2121

22-
/* Format: [numberPerPage, adapter]. Example: [10, SomePaginator::class] */
22+
/* Format: [adapter, numberPerPage]. Example: [SomePaginator::class, 10] */
2323
public array $paginate = [],
2424
) {
2525
}

src/Attributes/Unauthenticated.php

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Knuckles\Scribe\Attributes;
4+
5+
use Attribute;
6+
7+
#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
8+
class Unauthenticated
9+
{
10+
public function toArray()
11+
{
12+
return ["authenticated" => false];
13+
}
14+
}

src/Commands/GenerateDocumentation.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ class GenerateDocumentation extends Command
2929

3030
protected $description = 'Generate API documentation from your Laravel/Dingo routes.';
3131

32-
private DocumentationConfig $docConfig;
32+
protected DocumentationConfig $docConfig;
3333

34-
private bool $shouldExtract;
34+
protected bool $shouldExtract;
3535

36-
private bool $forcing;
36+
protected bool $forcing;
3737

3838
protected string $configName;
3939

src/Commands/Upgrade.php

+16-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Knuckles\Scribe\Commands;
44

55
use Illuminate\Console\Command;
6+
use Knuckles\Scribe\Tools\Globals;
67
use Shalvah\Upgrader\Upgrader;
78

89
class Upgrade extends Command
@@ -27,7 +28,9 @@ public function handle(): void
2728
return;
2829
}
2930

30-
$this->info("Welcome to the Scribe v3 to v4 upgrader.");
31+
$isMajorUpgrade = array_key_exists("default_group", $oldConfig) || array_key_exists("faker_seed", $oldConfig);
32+
33+
$isMajorUpgrade && $this->info("Welcome to the Scribe v3 to v4 upgrader.");
3134
$this->line("Checking for config file changes...");
3235

3336
$upgrader = Upgrader::ofConfigFile("config/$configName.php", __DIR__ . '/../../config/scribe.php')
@@ -53,6 +56,17 @@ public function handle(): void
5356
}
5457
$this->newLine();
5558

59+
if (!$isMajorUpgrade) {
60+
$this->info("✔ Done.");
61+
$this->info(sprintf("See the full changelog at https://github.com/knuckleswtf/scribe/blob/%s/CHANGELOG.md", Globals::SCRIBE_VERSION));
62+
return;
63+
}
64+
65+
$this->upgradeToV4();
66+
}
67+
68+
protected function upgradeToV4(): void
69+
{
5670
if ($this->confirm("Do you have any custom strategies?")) {
5771
$this->line('1. Add a new property <info>public ?ExtractedEndpointData $endpointData;</info>.');
5872
$this->line('2. Replace the <info>array $routeRules</info> parameter in __invoke() with <info>array $routeRules = []</info> .');
@@ -62,18 +76,10 @@ public function handle(): void
6276
if ($this->confirm("Did you customize the Blade templates used by Scribe?")) {
6377
$this->warn('A few minor changes were made to the templates. See the release announcement for details.');
6478
}
65-
$this->newLine();
66-
67-
$this->line("Scribe now supports PHP 8 attributes for annotations. "
68-
. "You can use both, but we recommend switching to attributes (see the docs).");
69-
if ($this->confirm("Would you like help in replacing your docblock tags with attributes?")) {
70-
$this->warn('Install our Rector package knuckleswtf/scribe-rector-t2a and run it.');
71-
}
72-
$this->warn("For attributes to work, you need to add the attribute strategies to your config file. See the release announcement for details.");
7379

7480
$this->newLine();
7581
$this->info("✔ Done.");
76-
$this->line("See the release announcement at <href=https://scribe.knuckles.wtf/v4>http://scribe.knuckles.wtf/v4</> for the full upgrade guide!");
82+
$this->line("See the release announcement at <href=https://scribe.knuckles.wtf/blog/laravel-v4>http://scribe.knuckles.wtf/blog/laravel-v4</> for the full upgrade guide!");
7783
}
7884

7985
}

src/Extracting/InstantiatesExampleModels.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ trait InstantiatesExampleModels
1818
*/
1919
protected function instantiateExampleModel(string $type, array $factoryStates = [], array $relations = [])
2020
{
21-
$configuredStrategies = $this->config->get('examples.models_source', ['factoryCreate', 'factoryMake', 'database']);
21+
$configuredStrategies = $this->config->get('examples.models_source', ['factoryCreate', 'factoryMake', 'databaseFirst']);
2222

2323
$strategies = [
2424
'factoryCreate' => fn() => $this->getExampleModelFromFactoryCreate($type, $factoryStates, $relations),
2525
'factoryMake' => fn() => $this->getExampleModelFromFactoryMake($type, $factoryStates, $relations),
26-
'database' => fn() => $this->getExampleModelFromDatabase($type, $relations),
26+
'databaseFirst' => fn() => $this->getExampleModelFromDatabaseFirst($type, $relations),
2727
];
2828

2929
foreach ($configuredStrategies as $strategyName) {
@@ -51,7 +51,7 @@ protected function getExampleModelFromFactoryMake(string $type, array $factorySt
5151
return $factory->make();
5252
}
5353

54-
protected function getExampleModelFromDatabase(string $type, array $relations = [])
54+
protected function getExampleModelFromDatabaseFirst(string $type, array $relations = [])
5555
{
5656
return $type::with($relations)->first();
5757
}

src/Extracting/Strategies/Metadata/GetFromDocBlocks.php

+14-13
Original file line numberDiff line numberDiff line change
@@ -60,42 +60,43 @@ protected function getEndpointGroupAndTitleDetails(DocBlock $methodDocBlock, Doc
6060
{
6161
foreach ($methodDocBlock->getTags() as $tag) {
6262
if ($tag->getName() === 'group') {
63-
$routeGroupParts = explode("\n", trim($tag->getContent()));
64-
$routeGroupName = array_shift($routeGroupParts);
65-
$routeGroupDescription = trim(implode("\n", $routeGroupParts));
63+
$endpointGroupParts = explode("\n", trim($tag->getContent()));
64+
$endpointGroupName = array_shift($endpointGroupParts);
65+
$endpointGroupDescription = trim(implode("\n", $endpointGroupParts));
6666

67-
// If the route has no title (the methodDocBlock's "short description"),
68-
// we'll assume the routeGroupDescription is actually the title
67+
// If the endpoint has no title (the methodDocBlock's "short description"),
68+
// we'll assume the endpointGroupDescription is actually the title
6969
// Something like this:
7070
// /**
71-
// * Fetch cars. <-- This is route title.
71+
// * Fetch cars. <-- This is endpoint title.
7272
// * @group Cars <-- This is group name.
7373
// * APIs for cars. <-- This is group description (not required).
7474
// **/
7575
// VS
7676
// /**
7777
// * @group Cars <-- This is group name.
78-
// * Fetch cars. <-- This is route title, NOT group description.
78+
// * Fetch cars. <-- This is endpoint title, NOT group description.
7979
// **/
8080

8181
// BTW, this is a spaghetti way of doing this.
8282
// It shall be refactored soon. Deus vult!💪
83+
// ...Or maybe not
8384
if (empty($methodDocBlock->getShortDescription())) {
84-
return [$routeGroupName, '', $routeGroupDescription];
85+
return [$endpointGroupName, '', $endpointGroupDescription];
8586
}
8687

87-
return [$routeGroupName, $routeGroupDescription, $methodDocBlock->getShortDescription()];
88+
return [$endpointGroupName, $endpointGroupDescription, $methodDocBlock->getShortDescription()];
8889
}
8990
}
9091

9192
// Fall back to the controller
9293
foreach ($controllerDocBlock->getTags() as $tag) {
9394
if ($tag->getName() === 'group') {
94-
$routeGroupParts = explode("\n", trim($tag->getContent()));
95-
$routeGroupName = array_shift($routeGroupParts);
96-
$routeGroupDescription = implode("\n", $routeGroupParts);
95+
$endpointGroupParts = explode("\n", trim($tag->getContent()));
96+
$endpointGroupName = array_shift($endpointGroupParts);
97+
$endpointGroupDescription = implode("\n", $endpointGroupParts);
9798

98-
return [$routeGroupName, $routeGroupDescription, $methodDocBlock->getShortDescription()];
99+
return [$endpointGroupName, $endpointGroupDescription, $methodDocBlock->getShortDescription()];
99100
}
100101
}
101102

src/Extracting/Strategies/Metadata/GetFromMetadataAttributes.php

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Knuckles\Scribe\Attributes\ResponseFromFile;
1212
use Knuckles\Scribe\Attributes\ResponseFromTransformer;
1313
use Knuckles\Scribe\Attributes\Subgroup;
14+
use Knuckles\Scribe\Attributes\Unauthenticated;
1415
use Knuckles\Scribe\Extracting\DatabaseTransactionHelpers;
1516
use Knuckles\Scribe\Extracting\InstantiatesExampleModels;
1617
use Knuckles\Scribe\Extracting\ParamHelpers;
@@ -30,6 +31,7 @@ class GetFromMetadataAttributes extends PhpAttributeStrategy
3031
Subgroup::class,
3132
Endpoint::class,
3233
Authenticated::class,
34+
Unauthenticated::class,
3335
];
3436

3537
protected function extractFromAttributes(

src/Extracting/Strategies/ResponseFields/GetFromResponseFieldTag.php

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Knuckles\Scribe\Extracting\Shared\ResponseFieldTools;
66
use Knuckles\Scribe\Extracting\Strategies\GetFieldsFromTagStrategy;
77
use Mpociot\Reflection\DocBlock;
8+
use Knuckles\Scribe\Tools\Utils as u;
89

910
class GetFromResponseFieldTag extends GetFieldsFromTagStrategy
1011
{

src/Extracting/Strategies/Responses/UseResponseAttributes.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected function getApiResourceResponse(ResponseFromApiResource $attributeInst
6161
$this->startDbTransaction();
6262
$content = ApiResourceResponseTools::fetch(
6363
$attributeInstance->name, $attributeInstance->collection, $modelInstantiator,
64-
$this->endpointData, $pagination, $attributeInstance->additionalData,
64+
$this->endpointData, $pagination, $attributeInstance->additional,
6565
);
6666
$this->endDbTransaction();
6767

@@ -76,7 +76,9 @@ protected function getTransformerResponse(ResponseFromTransformer $attributeInst
7676
{
7777
$modelInstantiator = fn() => $this->instantiateExampleModel($attributeInstance->model, $attributeInstance->factoryStates, $attributeInstance->with);
7878

79-
$pagination = ['perPage' => $attributeInstance->paginate[0], 'adapter' => $attributeInstance->paginate[1]];
79+
$pagination = [
80+
'perPage' => $attributeInstance->paginate[1] ?? null, 'adapter' => $attributeInstance->paginate[0]
81+
];
8082
$this->startDbTransaction();
8183
$content = TransformerResponseTools::fetch(
8284
$attributeInstance->name, $attributeInstance->collection, $modelInstantiator,

src/Extracting/Strategies/Responses/UseTransformerTags.php

+5-8
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,14 @@
44

55
use Knuckles\Camel\Extraction\ExtractedEndpointData;
66
use Exception;
7-
use Illuminate\Pagination\LengthAwarePaginator;
87
use Illuminate\Support\Arr;
98
use Knuckles\Scribe\Extracting\DatabaseTransactionHelpers;
109
use Knuckles\Scribe\Extracting\InstantiatesExampleModels;
1110
use Knuckles\Scribe\Extracting\RouteDocBlocker;
1211
use Knuckles\Scribe\Extracting\Shared\TransformerResponseTools;
1312
use Knuckles\Scribe\Extracting\Strategies\Strategy;
1413
use Knuckles\Scribe\Tools\AnnotationParser as a;
15-
use Knuckles\Scribe\Tools\ConsoleOutputUtils as c;
16-
use Knuckles\Scribe\Tools\ErrorHandlingUtils as e;
1714
use Knuckles\Scribe\Tools\Utils;
18-
use League\Fractal\Manager;
19-
use League\Fractal\Resource\Collection;
20-
use League\Fractal\Resource\Item;
2115
use Mpociot\Reflection\DocBlock\Tag;
2216
use ReflectionClass;
2317
use ReflectionFunctionAbstract;
@@ -132,11 +126,14 @@ private function getTransformerPaginatorData(array $tags): array
132126
return ['adapter' => null, 'perPage' => null];
133127
}
134128

135-
preg_match('/^\s*(.+?)\s+(\d+)?$/', $tag->getContent(), $result);
129+
preg_match('/^\s*(.+?)(\s+\d+)?$/', $tag->getContent(), $result);
136130
$paginatorAdapter = $result[1];
137131
$perPage = $result[2] ?? null;
132+
if ($perPage) {
133+
$perPage = trim($perPage);
134+
}
138135

139-
return ['adapter' => $paginatorAdapter, 'perPage' => $perPage];
136+
return ['adapter' => $paginatorAdapter, 'perPage' => $perPage ?: null];
140137
}
141138

142139
public function getTransformerResponseFromTags(array $tags): ?array

src/Extracting/Strategies/TagStrategyWithFormRequestFallback.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function __invoke(ExtractedEndpointData $endpointData, array $routeRules
2222
public function getParametersFromDocBlockInFormRequestOrMethod(Route $route, ReflectionFunctionAbstract $method): array
2323
{
2424
$classTags = RouteDocBlocker::getDocBlocksFromRoute($route)['class']?->getTags() ?: [];
25-
// If there's a FormRequest, we check there for tags.
25+
// If there's a FormRequest, w.e check there for tags.
2626
if ($formRequestClass = $this->getFormRequestReflectionClass($method)) {
2727
$formRequestDocBlock = new DocBlock($formRequestClass->getDocComment());
2828
$parametersFromFormRequest = $this->getFromTags($formRequestDocBlock->getTags(), $classTags);

src/GroupedEndpoints/GroupedEndpointsFromApp.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ protected function extractEndpointsInfoAndWriteToDisk(RouteMatcherInterface $rou
9595
*/
9696
private function extractEndpointsInfoFromLaravelApp(array $matches, array $cachedEndpoints, array $latestEndpointsData, array $groups): array
9797
{
98-
$generator = $this->makeExtractor();
98+
$extractor = $this->makeExtractor();
9999

100100
$parsedEndpoints = [];
101101

@@ -120,7 +120,7 @@ private function extractEndpointsInfoFromLaravelApp(array $matches, array $cache
120120

121121
try {
122122
c::info('Processing route: ' . c::getRouteRepresentation($route));
123-
$currentEndpointData = $generator->processRoute($route, $routeItem->getRules());
123+
$currentEndpointData = $extractor->processRoute($route, $routeItem->getRules());
124124
// If latest data is different from cached data, merge latest into current
125125
[$currentEndpointData, $index] = $this->mergeAnyEndpointDataUpdates($currentEndpointData, $cachedEndpoints, $latestEndpointsData, $groups);
126126

0 commit comments

Comments
 (0)