Skip to content

Commit 90d7a9f

Browse files
authored
Merge pull request #5 from mpociot/master
Update from base
2 parents ec04516 + 312d4df commit 90d7a9f

File tree

11 files changed

+99
-51
lines changed

11 files changed

+99
-51
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ $ php artisan api:update
240240

241241
As an optional parameter, you can use `--location` to tell the update command where your documentation can be found.
242242

243+
## Automatically add markdown to the beginning or end of the documentation
244+
If you wish to automatically add the same content to the docs every time you generate, you can add a `prepend.md` and/or `append.md` file to the source folder, and they will be included above and below the generated documentation.
245+
246+
**File locations:**
247+
- `public/docs/source/prepend.md` - Will be added after the front matter and info text
248+
- `public/docs/source/append.md` - Will be added at the end of the document
249+
243250
## Skip single routes
244251

245252
If you want to skip a single route from a list of routes that match a given prefix, you can use the `@hideFromAPIDocumentation` tag on the Controller method you do not want to document.

src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,9 @@ public function handle()
8989

9090
$parsedRoutes = [];
9191

92-
if ($this->option('router') === 'laravel') {
93-
foreach ($routeDomains as $routeDomain) {
94-
foreach ($routePrefixes as $routePrefix) {
95-
$parsedRoutes += $this->processRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware);
96-
}
97-
}
98-
} else {
99-
foreach ($routeDomains as $routeDomain) {
100-
foreach ($routePrefixes as $routePrefix) {
101-
$parsedRoutes += $this->processDingoRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware);
102-
}
92+
foreach ($routeDomains as $routeDomain) {
93+
foreach ($routePrefixes as $routePrefix) {
94+
$parsedRoutes += $this->processRoutes($generator, $allowedRoutes, $routeDomain, $routePrefix, $middleware);
10395
}
10496
}
10597
$parsedRoutes = collect($parsedRoutes)->groupBy('resource')->sort(function ($a, $b) {
@@ -119,6 +111,8 @@ private function writeMarkdown($parsedRoutes)
119111
$outputPath = $this->option('output');
120112
$targetFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'index.md';
121113
$compareFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'.compare.md';
114+
$prependFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'prepend.md';
115+
$appendFile = $outputPath.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'append.md';
122116

123117
$infoText = view('apidoc::partials.info')
124118
->with('outputPath', ltrim($outputPath, 'public/'))
@@ -164,12 +158,19 @@ private function writeMarkdown($parsedRoutes)
164158
});
165159
}
166160

161+
$prependFileContents = file_exists($prependFile)
162+
? file_get_contents($prependFile)."\n" : '';
163+
$appendFileContents = file_exists($appendFile)
164+
? "\n".file_get_contents($appendFile) : '';
165+
167166
$documentarian = new Documentarian();
168167

169168
$markdown = view('apidoc::documentarian')
170169
->with('writeCompareFile', false)
171170
->with('frontmatter', $frontmatter)
172171
->with('infoText', $infoText)
172+
->with('prependMd', $prependFileContents)
173+
->with('appendMd', $appendFileContents)
173174
->with('outputPath', $this->option('output'))
174175
->with('showPostmanCollectionButton', ! $this->option('noPostmanCollection'))
175176
->with('parsedRoutes', $parsedRouteOutput);
@@ -186,6 +187,8 @@ private function writeMarkdown($parsedRoutes)
186187
->with('writeCompareFile', true)
187188
->with('frontmatter', $frontmatter)
188189
->with('infoText', $infoText)
190+
->with('prependMd', $prependFileContents)
191+
->with('appendMd', $appendFileContents)
189192
->with('outputPath', $this->option('output'))
190193
->with('showPostmanCollectionButton', ! $this->option('noPostmanCollection'))
191194
->with('parsedRoutes', $parsedRouteOutput);

src/Mpociot/ApiDoc/Generators/AbstractGenerator.php

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ protected function getDocblockResponse($tags)
148148
*/
149149
protected function getParameters($routeData, $routeAction, $bindings)
150150
{
151-
$rules = $this->simplifyRules($this->getRouteRules($routeData['methods'], $routeAction['uses'], $bindings));
151+
$validationRules = $this->getRouteValidationRules($routeData['methods'], $routeAction['uses'], $bindings);
152+
$rules = $this->simplifyRules($validationRules);
152153

153154
foreach ($rules as $attribute => $ruleset) {
154155
$attributeData = [
@@ -168,27 +169,32 @@ protected function getParameters($routeData, $routeAction, $bindings)
168169
}
169170

170171
/**
171-
* Format the validation rules as plain array.
172+
* Format the validation rules as a plain array.
172173
*
173174
* @param array $rules
174175
*
175176
* @return array
176177
*/
177178
protected function simplifyRules($rules)
178179
{
179-
$simplifiedRules = Validator::make([], $rules)->getRules();
180+
// this will split all string rules into arrays of strings
181+
$rules = Validator::make([], $rules)->getRules();
180182

181-
if (count($simplifiedRules) === 0) {
182-
return $simplifiedRules;
183+
if (count($rules) === 0) {
184+
return $rules;
183185
}
184186

185-
$values = collect($simplifiedRules)
187+
// Laravel will ignore the nested array rules unless the key referenced exists and is an array
188+
// So we'll to create an empty array for each array attribute
189+
$values = collect($rules)
186190
->filter(function ($values) {
187191
return in_array('array', $values);
188192
})->map(function ($val, $key) {
189193
return [''];
190194
})->all();
191195

196+
// Now this will return the complete ruleset.
197+
// Nested array parameters will be present, with '*' replaced by '0'
192198
return Validator::make($values, $rules)->getRules();
193199
}
194200

@@ -287,10 +293,10 @@ protected function getRouteGroup($route)
287293
*
288294
* @return array
289295
*/
290-
protected function getRouteRules(array $routeMethods, $routeAction, $bindings)
296+
protected function getRouteValidationRules(array $routeMethods, $routeAction, $bindings)
291297
{
292-
list($class, $method) = explode('@', $routeAction);
293-
$reflection = new ReflectionClass($class);
298+
list($controller, $method) = explode('@', $routeAction);
299+
$reflection = new ReflectionClass($controller);
294300
$reflectionMethod = $reflection->getMethod($method);
295301

296302
foreach ($reflectionMethod->getParameters() as $parameter) {
@@ -357,13 +363,13 @@ protected function splitValuePairs($parameters, $first = 'is ', $last = 'or ')
357363

358364
/**
359365
* @param string $rule
360-
* @param string $ruleName
366+
* @param string $attribute
361367
* @param array $attributeData
362368
* @param int $seed
363369
*
364370
* @return void
365371
*/
366-
protected function parseRule($rule, $ruleName, &$attributeData, $seed, $routeData)
372+
protected function parseRule($rule, $attribute, &$attributeData, $seed, $routeData)
367373
{
368374
$faker = Factory::create();
369375
$faker->seed(crc32($seed));
@@ -510,7 +516,7 @@ protected function parseRule($rule, $ruleName, &$attributeData, $seed, $routeDat
510516
$attributeData['value'] = $faker->timezone;
511517
break;
512518
case 'exists':
513-
$fieldName = isset($parameters[1]) ? $parameters[1] : $ruleName;
519+
$fieldName = isset($parameters[1]) ? $parameters[1] : $attribute;
514520
$attributeData['description'][] = Description::parse($rule)->with([Str::singular($parameters[0]), $fieldName])->getDescription();
515521
break;
516522
case 'active_url':
@@ -627,7 +633,7 @@ protected function parseStringRule($rules)
627633

628634
// The format for specifying validation rules and parameters follows an
629635
// easy {rule}:{parameters} formatting convention. For instance the
630-
// rule "Max:3" states that the value may only be three letters.
636+
// rule "max:3" states that the value may only be three letters.
631637
if (strpos($rules, ':') !== false) {
632638
list($rules, $parameter) = explode(':', $rules, 2);
633639

src/resources/views/documentarian.blade.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
<!-- START_INFO -->
55
{!! $infoText !!}
66
<!-- END_INFO -->
7-
7+
{!! $prependMd !!}
88
@foreach($parsedRoutes as $group => $routes)
99
@if($group)
1010
#{!! $group !!}
1111
@endif
1212
@foreach($routes as $parsedRoute)
1313
@if($writeCompareFile === true)
14-
{!! $parsedRoute['output']!!}
14+
{!! $parsedRoute['output'] !!}
1515
@else
16-
{!! isset($parsedRoute['modified_output']) ? $parsedRoute['modified_output'] : $parsedRoute['output']!!}
16+
{!! isset($parsedRoute['modified_output']) ? $parsedRoute['modified_output'] : $parsedRoute['output'] !!}
1717
@endif
1818
@endforeach
19-
@endforeach
19+
@endforeach{!! $appendMd !!}

src/resources/views/partials/route.blade.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
> Example request:
1111

1212
```bash
13-
curl -X {{$parsedRoute['methods'][0]}} "{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \
14-
-H "Accept: application/json"@if(count($parsedRoute['parameters'])) \
13+
curl -X {{$parsedRoute['methods'][0]}} {{$parsedRoute['methods'][0] == 'GET' ? '-G ' : ''}}"{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \
14+
-H "Accept: application/json"@if(count($parsedRoute['parameters'])) \
1515
@foreach($parsedRoute['parameters'] as $attribute => $parameter)
16-
-d "{{$attribute}}"="{{$parameter['value']}}" \
16+
-d "{{$attribute}}"="{{$parameter['value']}}" @if(! ($loop->last))\
17+
@endif
1718
@endforeach
1819
@endif
1920

@@ -26,7 +27,7 @@
2627
"url": "{{ rtrim(config('app.docs_url') ?: config('app.url'), '/') }}/{{ ltrim($parsedRoute['uri'], '/') }}",
2728
"method": "{{$parsedRoute['methods'][0]}}",
2829
@if(count($parsedRoute['parameters']))
29-
"data": {!! str_replace(' ',' ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT)) !!},
30+
"data": {!! str_replace("\n}","\n }", str_replace(' ',' ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT))) !!},
3031
@endif
3132
"headers": {
3233
"accept": "application/json"

tests/Fixtures/append.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Appended Markdown
2+
3+
This markdown should be added to the end of generated docs

tests/Fixtures/index.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ It can also be multiple lines long.
3030
> Example request:
3131
3232
```bash
33-
curl -X GET "http://localhost/api/test" \
34-
-H "Accept: application/json"
33+
curl -X GET -G "http://localhost/api/test" \
34+
-H "Accept: application/json"
3535
```
3636

3737
```javascript
@@ -68,8 +68,8 @@ null
6868
> Example request:
6969
7070
```bash
71-
curl -X GET "http://localhost/api/fetch" \
72-
-H "Accept: application/json"
71+
curl -X GET -G "http://localhost/api/fetch" \
72+
-H "Accept: application/json"
7373
```
7474

7575
```javascript
@@ -106,3 +106,4 @@ $.ajax(settings).done(function (response) {
106106

107107
<!-- END_960a1b2b0f0f4dde8ce993307397f9c4 -->
108108

109+

tests/Fixtures/prepend.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Prepended Markdown
2+
3+
This markdown should be added to the start of generated docs

tests/Fixtures/resource_index.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ Welcome to the generated API reference.
2727
> Example request:
2828
2929
```bash
30-
curl -X GET "http://localhost/api/user" \
31-
-H "Accept: application/json"
30+
curl -X GET -G "http://localhost/api/user" \
31+
-H "Accept: application/json"
3232
```
3333

3434
```javascript
@@ -67,8 +67,8 @@ $.ajax(settings).done(function (response) {
6767
> Example request:
6868
6969
```bash
70-
curl -X GET "http://localhost/api/user/create" \
71-
-H "Accept: application/json"
70+
curl -X GET -G "http://localhost/api/user/create" \
71+
-H "Accept: application/json"
7272
```
7373

7474
```javascript
@@ -108,7 +108,7 @@ $.ajax(settings).done(function (response) {
108108
109109
```bash
110110
curl -X POST "http://localhost/api/user" \
111-
-H "Accept: application/json"
111+
-H "Accept: application/json"
112112
```
113113

114114
```javascript
@@ -140,8 +140,8 @@ $.ajax(settings).done(function (response) {
140140
> Example request:
141141
142142
```bash
143-
curl -X GET "http://localhost/api/user/{user}" \
144-
-H "Accept: application/json"
143+
curl -X GET -G "http://localhost/api/user/{user}" \
144+
-H "Accept: application/json"
145145
```
146146

147147
```javascript
@@ -180,8 +180,8 @@ $.ajax(settings).done(function (response) {
180180
> Example request:
181181
182182
```bash
183-
curl -X GET "http://localhost/api/user/{user}/edit" \
184-
-H "Accept: application/json"
183+
curl -X GET -G "http://localhost/api/user/{user}/edit" \
184+
-H "Accept: application/json"
185185
```
186186

187187
```javascript
@@ -221,7 +221,7 @@ $.ajax(settings).done(function (response) {
221221
222222
```bash
223223
curl -X PUT "http://localhost/api/user/{user}" \
224-
-H "Accept: application/json"
224+
-H "Accept: application/json"
225225
```
226226

227227
```javascript
@@ -256,7 +256,7 @@ $.ajax(settings).done(function (response) {
256256
257257
```bash
258258
curl -X DELETE "http://localhost/api/user/{user}" \
259-
-H "Accept: application/json"
259+
-H "Accept: application/json"
260260
```
261261

262262
```javascript
@@ -282,3 +282,4 @@ $.ajax(settings).done(function (response) {
282282

283283
<!-- END_4bb7fb4a7501d3cb1ed21acfc3b205a9 -->
284284

285+

tests/GenerateDocumentationTest.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ public function testCanParseResourceRoutes()
123123
'--routePrefix' => 'api/*',
124124
]);
125125
$fixtureMarkdown = __DIR__.'/Fixtures/resource_index.md';
126-
$gneratedMarkdown = __DIR__.'/../public/docs/source/index.md';
127-
$this->assertFilesHaveSameContent($fixtureMarkdown, $gneratedMarkdown);
126+
$generatedMarkdown = __DIR__.'/../public/docs/source/index.md';
127+
$this->assertFilesHaveSameContent($fixtureMarkdown, $generatedMarkdown);
128128
}
129129

130130
public function testGeneratedMarkdownFileIsCorrect()
@@ -143,6 +143,29 @@ public function testGeneratedMarkdownFileIsCorrect()
143143
$this->assertFilesHaveSameContent($fixtureMarkdown, $compareMarkdown);
144144
}
145145

146+
public function testCanPrependAndAppendDataToGeneratedMarkdown()
147+
{
148+
RouteFacade::get('/api/test', TestController::class.'@parseMethodDescription');
149+
RouteFacade::get('/api/fetch', TestController::class.'@fetchRouteResponse');
150+
151+
$this->artisan('api:generate', [
152+
'--routePrefix' => 'api/*',
153+
]);
154+
155+
$prependMarkdown = __DIR__.'/Fixtures/prepend.md';
156+
$appendMarkdown = __DIR__.'/Fixtures/append.md';
157+
copy($prependMarkdown, __DIR__.'/../public/docs/source/prepend.md');
158+
copy($appendMarkdown, __DIR__.'/../public/docs/source/append.md');
159+
160+
$this->artisan('api:generate', [
161+
'--routePrefix' => 'api/*',
162+
]);
163+
164+
$generatedMarkdown = __DIR__.'/../public/docs/source/index.md';
165+
$this->assertContainsRaw($this->getFileContents($prependMarkdown), $this->getFileContents($generatedMarkdown));
166+
$this->assertContainsRaw($this->getFileContents($appendMarkdown), $this->getFileContents($generatedMarkdown));
167+
}
168+
146169
public function testAddsBindingsToGetRouteRules()
147170
{
148171
RouteFacade::get('/api/test/{foo}', TestController::class.'@addRouteBindingsToRequestClass');

0 commit comments

Comments
 (0)