Skip to content

Commit e819439

Browse files
committed
Added Dingo support
Added support for route model bindings Added grouping of controllers
1 parent e5c2844 commit e819439

File tree

6 files changed

+331
-84
lines changed

6 files changed

+331
-84
lines changed

src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php

Lines changed: 109 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
namespace Mpociot\ApiDoc\Commands;
44

55
use Illuminate\Console\Command;
6-
use Mpociot\ApiDoc\ApiDocGenerator;
6+
use Illuminate\Support\Collection;
77
use Illuminate\Support\Facades\Route;
8+
use Mpociot\ApiDoc\Generators\AbstractGenerator;
9+
use Mpociot\ApiDoc\Generators\DingoGenerator;
10+
use Mpociot\ApiDoc\Generators\LaravelGenerator;
811
use Mpociot\Documentarian\Documentarian;
912

1013
class GenerateDocumentation extends Command
@@ -19,6 +22,8 @@ class GenerateDocumentation extends Command
1922
{--routePrefix= : The route prefix to use for generation}
2023
{--routes=* : The route names to use for generation}
2124
{--actAsUserId= : The user ID to use for API response calls}
25+
{--router=laravel : The router to be used (Laravel or Dingo)}
26+
{--bindings= : Route Model Bindings}
2227
';
2328

2429
/**
@@ -45,46 +50,35 @@ public function __construct()
4550
*/
4651
public function handle()
4752
{
53+
if ($this->option('router') === 'laravel') {
54+
$generator = new LaravelGenerator();
55+
} else {
56+
$generator = new DingoGenerator();
57+
}
58+
4859
$allowedRoutes = $this->option('routes');
4960
$routePrefix = $this->option('routePrefix');
50-
$actAs = $this->option('actAsUserId');
61+
62+
$this->setUserToBeImpersonated($this->option('actAsUserId'));
5163

5264
if ($routePrefix === null && ! count($allowedRoutes)) {
5365
$this->error('You must provide either a route prefix or a route to generate the documentation.');
5466

5567
return false;
5668
}
5769

58-
if ($actAs !== null) {
59-
if (version_compare($this->laravel->version(), '5.2.0', '<')) {
60-
$userModel = config('auth.model');
61-
$user = $userModel::find($actAs);
62-
$this->laravel['auth']->setUser($user);
63-
} else {
64-
$userModel = config('auth.providers.users.model');
65-
$user = $userModel::find($actAs);
66-
$this->laravel['auth']->guard()->setUser($user);
67-
}
68-
}
69-
70-
$routes = Route::getRoutes();
71-
72-
$generator = new ApiDocGenerator();
73-
74-
/* @var \Illuminate\Routing\Route $route */
75-
$parsedRoutes = [];
76-
foreach ($routes as $route) {
77-
if (in_array($route->getName(), $allowedRoutes) || str_is($routePrefix, $route->getUri())) {
78-
$parsedRoutes[] = $generator->processRoute($route);
79-
$this->info('Processed route: '.$route->getUri());
80-
}
70+
if ($this->option('router') === 'laravel') {
71+
$parsedRoutes = $this->processLaravelRoutes($generator, $allowedRoutes, $routePrefix);
72+
} else {
73+
$parsedRoutes = $this->processDingoRoutes($generator, $allowedRoutes, $routePrefix);
8174
}
75+
$parsedRoutes = collect($parsedRoutes)->sortBy('resource')->groupBy('resource');
8276

8377
$this->writeMarkdown($parsedRoutes);
8478
}
8579

8680
/**
87-
* @param array $parsedRoutes
81+
* @param Collection $parsedRoutes
8882
*
8983
* @return void
9084
*/
@@ -94,7 +88,7 @@ private function writeMarkdown($parsedRoutes)
9488

9589
$documentarian = new Documentarian();
9690

97-
$markdown = view('apidoc::documentarian')->with('parsedRoutes', $parsedRoutes);
91+
$markdown = view('apidoc::documentarian')->with('parsedRoutes', $parsedRoutes->all());
9892

9993
if (! is_dir($outputPath)) {
10094
$documentarian->create($outputPath);
@@ -110,4 +104,92 @@ private function writeMarkdown($parsedRoutes)
110104

111105
$this->info('Wrote HTML documentation to: '.$outputPath.'/public/index.html');
112106
}
107+
108+
/**
109+
* @return array
110+
*/
111+
private function getBindings()
112+
{
113+
$bindings = $this->option('bindings');
114+
if (empty($bindings)) {
115+
return [];
116+
}
117+
$bindings = explode('|', $bindings);
118+
$resultBindings = [];
119+
foreach ($bindings as $binding) {
120+
list($name, $id) = explode(',', $binding);
121+
$resultBindings[$name] = $id;
122+
}
123+
return $resultBindings;
124+
}
125+
126+
/**
127+
* @param $actAs
128+
*/
129+
private function setUserToBeImpersonated($actAs)
130+
{
131+
if (!empty($actAs)) {
132+
if (version_compare($this->laravel->version(), '5.2.0', '<')) {
133+
$userModel = config('auth.model');
134+
$user = $userModel::find($actAs);
135+
$this->laravel['auth']->setUser($user);
136+
} else {
137+
$userModel = config('auth.providers.users.model');
138+
$user = $userModel::find($actAs);
139+
$this->laravel['auth']->guard()->setUser($user);
140+
}
141+
}
142+
}
143+
144+
/**
145+
* @return mixed
146+
*/
147+
private function getRoutes()
148+
{
149+
if ($this->option('router') === 'laravel') {
150+
return Route::getRoutes();
151+
} else {
152+
return app('Dingo\Api\Routing\Router')->getRoutes()[$this->option('routePrefix')];
153+
}
154+
}
155+
156+
/**
157+
* @param AbstractGenerator $generator
158+
* @param $allowedRoutes
159+
* @param $routePrefix
160+
* @return array
161+
*/
162+
private function processLaravelRoutes(AbstractGenerator $generator, $allowedRoutes, $routePrefix)
163+
{
164+
$routes = $this->getRoutes();
165+
$bindings = $this->getBindings();
166+
$parsedRoutes = [];
167+
foreach ($routes as $route) {
168+
if (in_array($route->getName(), $allowedRoutes) || str_is($routePrefix, $route->getUri())) {
169+
$parsedRoutes[] = $generator->processRoute($route, $bindings);
170+
$this->info('Processed route: '.$route->getUri());
171+
}
172+
}
173+
return $parsedRoutes;
174+
}
175+
176+
/**
177+
* @param AbstractGenerator $generator
178+
* @param $allowedRoutes
179+
* @param $routePrefix
180+
* @return array
181+
*/
182+
private function processDingoRoutes(AbstractGenerator $generator, $allowedRoutes, $routePrefix)
183+
{
184+
$routes = $this->getRoutes();
185+
$bindings = $this->getBindings();
186+
$parsedRoutes = [];
187+
foreach ($routes as $route) {
188+
if (empty($allowedRoutes) || in_array($route->getName(), $allowedRoutes) || str_is($routePrefix, $route->uri())) {
189+
$parsedRoutes[] = $generator->processRoute($route, $bindings);
190+
$this->info('Processed route: '.$route->uri());
191+
}
192+
}
193+
return $parsedRoutes;
194+
}
113195
}

src/Mpociot/ApiDoc/ApiDocGenerator.php renamed to src/Mpociot/ApiDoc/Generators/AbstractGenerator.php

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,38 @@
11
<?php
22

3-
namespace Mpociot\ApiDoc;
3+
namespace Mpociot\ApiDoc\Generators;
44

55
use Faker\Factory;
66
use ReflectionClass;
77
use Illuminate\Support\Str;
88
use Illuminate\Routing\Route;
9-
use Illuminate\Support\Facades\App;
109
use phpDocumentor\Reflection\DocBlock;
11-
use Illuminate\Support\Facades\Request;
1210
use Illuminate\Support\Facades\Validator;
1311
use Illuminate\Foundation\Http\FormRequest;
1412

15-
class ApiDocGenerator
13+
abstract class AbstractGenerator
1614
{
15+
1716
/**
18-
* @param \Illuminate\Routing\Route $route
17+
* @param Route $route
18+
* @return mixed
19+
*/
20+
abstract protected function getUri(Route $route);
21+
22+
/**
23+
* @param \Illuminate\Routing\Route $route
24+
* @param array $bindings
1925
*
2026
* @return array
2127
*/
22-
public function processRoute(Route $route)
23-
{
24-
$routeAction = $route->getAction();
25-
$response = $this->getRouteResponse($route);
26-
$routeDescription = $this->getRouteDescription($routeAction['uses']);
27-
if ($response->headers->get('Content-Type') === 'application/json') {
28-
$content = json_encode(json_decode($response->getContent()), JSON_PRETTY_PRINT);
29-
} else {
30-
$content = $response->getContent();
31-
}
32-
$routeData = [
33-
'title' => $routeDescription['short'],
34-
'description' => $routeDescription['long'],
35-
'methods' => $route->getMethods(),
36-
'uri' => $route->getUri(),
37-
'parameters' => [],
38-
'response' => $content,
39-
];
28+
abstract public function processRoute(Route $route, $bindings = []);
4029

30+
/**
31+
* @param array $routeData
32+
* @param array $routeAction
33+
* @return mixed
34+
*/
35+
protected function getParameters($routeData, $routeAction) {
4136
$validator = Validator::make([], $this->getRouteRules($routeAction['uses']));
4237
foreach ($validator->getRules() as $attribute => $rules) {
4338
$attributeData = [
@@ -61,19 +56,36 @@ public function processRoute(Route $route)
6156
*
6257
* @return \Illuminate\Http\Response
6358
*/
64-
private function getRouteResponse(Route $route)
59+
protected function getRouteResponse(Route $route, $bindings)
6560
{
61+
$uri = $this->addRouteModelBindings($route, $bindings);
62+
6663
$methods = $route->getMethods();
6764

68-
return $this->callRoute(array_shift($methods), $route->getUri());
65+
return $this->callRoute(array_shift($methods), $uri);
66+
}
67+
68+
69+
/**
70+
* @param Route $route
71+
* @param array $bindings
72+
* @return mixed
73+
*/
74+
protected function addRouteModelBindings(Route $route, $bindings)
75+
{
76+
$uri = $this->getUri($route);
77+
foreach ($bindings as $model => $id) {
78+
$uri = str_replace('{'.$model.'}', $id, $uri);
79+
}
80+
return $uri;
6981
}
7082

7183
/**
7284
* @param \Illuminate\Routing\Route $route
7385
*
7486
* @return string
7587
*/
76-
private function getRouteDescription($route)
88+
protected function getRouteDescription($route)
7789
{
7890
list($class, $method) = explode('@', $route);
7991
$reflection = new ReflectionClass($class);
@@ -88,12 +100,32 @@ private function getRouteDescription($route)
88100
];
89101
}
90102

103+
91104
/**
92-
* @param \Illuminate\Routing\Route $route
105+
* @param string $route
106+
*
107+
* @return string
108+
*/
109+
protected function getRouteGroup($route)
110+
{
111+
list($class, $method) = explode('@', $route);
112+
$reflection = new ReflectionClass($class);
113+
$comment = $reflection->getDocComment();
114+
$phpdoc = new DocBlock($comment);
115+
foreach ($phpdoc->getTags() as $tag) {
116+
if ($tag->getName() === 'resource') {
117+
return $tag->getContent();
118+
}
119+
}
120+
return 'general';
121+
}
122+
123+
/**
124+
* @param $route
93125
*
94126
* @return array
95127
*/
96-
private function getRouteRules($route)
128+
protected function getRouteRules($route)
97129
{
98130
list($class, $method) = explode('@', $route);
99131
$reflection = new ReflectionClass($class);
@@ -320,27 +352,7 @@ protected function parseRule($rule, &$attributeData)
320352
*
321353
* @return \Illuminate\Http\Response
322354
*/
323-
public function callRoute($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
324-
{
325-
$kernel = App::make('Illuminate\Contracts\Http\Kernel');
326-
App::instance('middleware.disable', true);
327-
328-
$server = [
329-
'CONTENT_TYPE' => 'application/json',
330-
'Accept' => 'application/json',
331-
];
332-
333-
$request = Request::create(
334-
$uri, $method, $parameters,
335-
$cookies, $files, $this->transformHeadersToServerVars($server), $content
336-
);
337-
338-
$response = $kernel->handle($request);
339-
340-
$kernel->terminate($request, $response);
341-
342-
return $response;
343-
}
355+
abstract public function callRoute($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null);
344356

345357
/**
346358
* Transform headers array to array of $_SERVER vars with HTTP_* format.

0 commit comments

Comments
 (0)