Skip to content

Commit 5647eda

Browse files
committed
Parse @group tag on method properly - fixes #564, #561
1 parent fdc7a72 commit 5647eda

File tree

7 files changed

+97
-28
lines changed

7 files changed

+97
-28
lines changed

TODO.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Major
22
- Bring `bindings` outside of `response_calls`
33
- Should `routes.*.apply.response_calls.headers` be replaced by `routes.*.apply.headers`?
4+
- Should we move HTML generation from Blade to fully PHP? (L)

resources/views/documentarian.blade.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
<!-- END_INFO -->
77
{!! $prependMd !!}
88
@foreach($parsedRoutes as $groupName => $routes)
9-
@if($groupName)
109
#{!! $groupName !!}
11-
@endif
1210
{{-- We pick the first non-empty description we see. --}}
1311
{!! array_first($routes, function ($route) { return $route['groupDescription'] !== ''; })['groupDescription'] ?? '' !!}
1412
@foreach($routes as $parsedRoute)

src/Commands/GenerateDocumentation.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ public function __construct(RouteMatcher $routeMatcher)
6060
*/
6161
public function handle()
6262
{
63-
// Using a global static variable here, so fuck off if you don't like it
64-
// Also, the --verbose option is included with all Artisan commands
63+
// Using a global static variable here, so fuck off if you don't like it.
64+
// Also, the --verbose option is included with all Artisan commands.
6565
Flags::$shouldBeVerbose = $this->option('verbose');
6666

6767
$this->docConfig = new DocumentationConfig(config('apidoc'));
@@ -82,13 +82,14 @@ public function handle()
8282

8383
$generator = new Generator($this->docConfig);
8484
$parsedRoutes = $this->processRoutes($generator, $routes);
85-
$parsedRoutes = collect($parsedRoutes)->groupBy('groupName')
85+
$groupedRoutes = collect($parsedRoutes)
86+
->groupBy('groupName')
8687
->sortBy(static function ($group) {
8788
/* @var $group Collection */
8889
return $group->first()['groupName'];
8990
}, SORT_NATURAL);
9091

91-
$this->writeMarkdown($parsedRoutes);
92+
$this->writeMarkdown($groupedRoutes);
9293
}
9394

9495
/**

src/Tools/Generator.php

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ public function processRoute(Route $route, array $rulesToApply = [])
5757
$controller = new ReflectionClass($class);
5858
$method = $controller->getMethod($method);
5959

60-
list($routeGroupName, $routeGroupDescription) = $this->getRouteGroup($controller, $method);
6160

6261
$docBlock = $this->parseDocBlock($method);
62+
list($routeGroupName, $routeGroupDescription, $routeTitle) = $this->getRouteGroup($controller, $docBlock);
6363
$bodyParameters = $this->getBodyParameters($method, $docBlock['tags']);
6464
$queryParameters = $this->getQueryParameters($method, $docBlock['tags']);
6565
$content = ResponseResolver::getResponse($route, $docBlock['tags'], [
@@ -72,7 +72,7 @@ public function processRoute(Route $route, array $rulesToApply = [])
7272
'id' => md5($this->getUri($route).':'.implode($this->getMethods($route))),
7373
'groupName' => $routeGroupName,
7474
'groupDescription' => $routeGroupDescription,
75-
'title' => $docBlock['short'],
75+
'title' => $routeTitle ?: $docBlock['short'],
7676
'description' => $docBlock['long'],
7777
'methods' => $this->getMethods($route),
7878
'uri' => $this->getUri($route),
@@ -271,24 +271,40 @@ protected function parseDocBlock(ReflectionMethod $method)
271271

272272
/**
273273
* @param ReflectionClass $controller
274-
* @param ReflectionMethod $method
274+
* @param array $methodDocBlock
275275
*
276-
* @return array The route group name and description
276+
* @return array The route group name, the group description, ad the route title
277277
*/
278-
protected function getRouteGroup(ReflectionClass $controller, ReflectionMethod $method)
278+
protected function getRouteGroup(ReflectionClass $controller, array $methodDocBlock)
279279
{
280280
// @group tag on the method overrides that on the controller
281-
$docBlockComment = $method->getDocComment();
282-
if ($docBlockComment) {
283-
$phpdoc = new DocBlock($docBlockComment);
284-
foreach ($phpdoc->getTags() as $tag) {
281+
if (!empty($methodDocBlock['tags'])) {
282+
foreach ($methodDocBlock['tags'] as $tag) {
285283
if ($tag->getName() === 'group') {
286-
$routeGroup = trim($tag->getContent());
287-
$routeGroupParts = explode("\n", $tag->getContent());
284+
$routeGroupParts = explode("\n", trim($tag->getContent()));
288285
$routeGroupName = array_shift($routeGroupParts);
289-
$routeGroupDescription = implode("\n", $routeGroupParts);
290-
291-
return [$routeGroupName, $routeGroupDescription];
286+
$routeGroupDescription = trim(implode("\n", $routeGroupParts));
287+
288+
// If the route has no title (aka "short"),
289+
// we'll assume the routeGroupDescription is actually the title
290+
// Something like this:
291+
// /**
292+
// * Fetch cars. <-- This is route title.
293+
// * @group Cars <-- This is group name.
294+
// * APIs for cars. <-- This is group description (not required).
295+
// **/
296+
// VS
297+
// /**
298+
// * @group Cars <-- This is group name.
299+
// * Fetch cars. <-- This is route title, NOT group description.
300+
// **/
301+
302+
// BTW, this is a spaghetti way of doing this.
303+
// It shall be refactored soon. Deus vult!💪
304+
if (empty($methodDocBlock['short'])) {
305+
return [$routeGroupName, '', $routeGroupDescription];
306+
}
307+
return [$routeGroupName, $routeGroupDescription, $methodDocBlock['short']];
292308
}
293309
}
294310
}
@@ -298,16 +314,16 @@ protected function getRouteGroup(ReflectionClass $controller, ReflectionMethod $
298314
$phpdoc = new DocBlock($docBlockComment);
299315
foreach ($phpdoc->getTags() as $tag) {
300316
if ($tag->getName() === 'group') {
301-
$routeGroupParts = explode("\n", $tag->getContent());
317+
$routeGroupParts = explode("\n", trim($tag->getContent()));
302318
$routeGroupName = array_shift($routeGroupParts);
303319
$routeGroupDescription = implode("\n", $routeGroupParts);
304320

305-
return [$routeGroupName, $routeGroupDescription];
321+
return [$routeGroupName, $routeGroupDescription, $methodDocBlock['short']];
306322
}
307323
}
308324
}
309325

310-
return [$this->config->get(('default_group')), ''];
326+
return [$this->config->get(('default_group')), '', $methodDocBlock['short']];
311327
}
312328

313329
private function normalizeParameterType($type)

src/Tools/RouteMatcher.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public function getRoutesToBeDocumented(array $routeRules, bool $usingDingoRoute
4848
return $matchedRoutes;
4949
}
5050

51+
// TODO we should cache the results of this, for Laravel routes at least,
52+
// to improve performance, since this method gets called
53+
// for each ruleset in the config file. Not a high priority, though.
5154
private function getAllRoutes(bool $usingDingoRouter, array $versions = [])
5255
{
5356
if (! $usingDingoRouter) {

tests/Fixtures/TestController.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,39 @@ public function withGroupOverride()
3333
return '';
3434
}
3535

36+
/**
37+
* This is also in Group B. No route description. Route title before gropp.
38+
*
39+
* @group Group B
40+
*/
41+
public function withGroupOverride2()
42+
{
43+
return '';
44+
}
45+
46+
/**
47+
* @group Group B
48+
*
49+
* This is also in Group B. Route title after group.
50+
*/
51+
public function withGroupOverride3()
52+
{
53+
return '';
54+
}
55+
56+
/**
57+
* This is in Group C. Route title before group.
58+
*
59+
* @group Group C
60+
*
61+
* Group description after group.
62+
*
63+
*/
64+
public function withGroupOverride4()
65+
{
66+
return '';
67+
}
68+
3669
/**
3770
* @bodyParam user_id int required The id of the user. Example: 9
3871
* @bodyParam room_id string The id of the room.

tests/Unit/GeneratorTestCase.php

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Orchestra\Testbench\TestCase;
66
use Mpociot\ApiDoc\Tools\Generator;
7-
use Illuminate\Support\Facades\Storage;
87
use Mpociot\ApiDoc\Tools\DocumentationConfig;
98
use Mpociot\ApiDoc\ApiDocGeneratorServiceProvider;
109

@@ -222,10 +221,28 @@ public function can_parse_route_group()
222221
/** @test */
223222
public function method_can_override_controller_group()
224223
{
225-
$route = $this->createRoute('GET', '/api/test', 'withGroupOverride');
226-
$routeGroup = $this->generator->processRoute($route)['groupName'];
227-
228-
$this->assertSame('Group B', $routeGroup);
224+
$route = $this->createRoute('GET', '/group/1', 'withGroupOverride');
225+
$parsedRoute = $this->generator->processRoute($route);
226+
$this->assertSame('Group B', $parsedRoute['groupName']);
227+
$this->assertSame('', $parsedRoute['groupDescription']);
228+
229+
$route = $this->createRoute('GET', '/group/2', 'withGroupOverride2');
230+
$parsedRoute = $this->generator->processRoute($route);
231+
$this->assertSame('Group B', $parsedRoute['groupName']);
232+
$this->assertSame('', $parsedRoute['groupDescription']);
233+
$this->assertSame('This is also in Group B. No route description. Route title before gropp.', $parsedRoute['title']);
234+
235+
$route = $this->createRoute('GET', '/group/3', 'withGroupOverride3');
236+
$parsedRoute = $this->generator->processRoute($route);
237+
$this->assertSame('Group B', $parsedRoute['groupName']);
238+
$this->assertSame('', $parsedRoute['groupDescription']);
239+
$this->assertSame('This is also in Group B. Route title after group.', $parsedRoute['title']);
240+
241+
$route = $this->createRoute('GET', '/group/4', 'withGroupOverride4');
242+
$parsedRoute = $this->generator->processRoute($route);
243+
$this->assertSame('Group C', $parsedRoute['groupName']);
244+
$this->assertSame('Group description after group.', $parsedRoute['groupDescription']);
245+
$this->assertSame('This is in Group C. Route title before group.', $parsedRoute['title']);
229246
}
230247

231248
/** @test */

0 commit comments

Comments
 (0)