Browse Source

Merge pull request #2 from mpociot/master

Update from base
Shalvah A 6 years ago
parent
commit
30ca099759

+ 3 - 0
.gitignore

@@ -3,3 +3,6 @@ composer.lock
 .php_cs.cache
 /vendor/
 /public
+.idea/
+coverage.xml
+results.xml

+ 2 - 2
.travis.yml

@@ -10,10 +10,10 @@ before_script:
   - travis_retry composer install --prefer-dist --no-interaction
 
 script:
-  - vendor/bin/phpunit --coverage-clover=coverage.xml
+  - composer test-ci
 
 before_install:
   - pip install --user codecov
 
 after_success:
-  - codecov
+  - codecov

+ 49 - 0
CHANGELOG.md

@@ -0,0 +1,49 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). If you make a pull request to this project, please update this changelog.
+
+## Unreleased
+### Added
+
+### Changed
+
+### Fixed
+
+### Removed
+
+## [2.1.2] - 10th September, 2018
+### Fixed
+- Set correct HTTP method when parsing FormRequest (https://github.com/mpociot/laravel-apidoc-generator/pull/314)
+
+## [2.1.1] - 10th September, 2018
+### Fixed
+- Print the correct file path of generated documentation (https://github.com/mpociot/laravel-apidoc-generator/pull/311)
+- Removed any extra slashes in URLs displayed in code samples (https://github.com/mpociot/laravel-apidoc-generator/pull/310)
+- Response calls are now also made for only GET in DIngo Router (https://github.com/mpociot/laravel-apidoc-generator/pull/309)
+- HEAD routes are no longer automatically generated for GET routes in DIngo Router (https://github.com/mpociot/laravel-apidoc-generator/pull/309)
+
+## [2.1.0] - 9th September, 2018
+### Added
+- Added support for multiple route domains (https://github.com/mpociot/laravel-apidoc-generator/pull/255) 
+- Added support for descriptions in custom validation rules (https://github.com/mpociot/laravel-apidoc-generator/pull/208)
+- Added support for multiple route prefixes (https://github.com/mpociot/laravel-apidoc-generator/pull/203)
+- Added support for formatting and `<aside>` tags (https://github.com/mpociot/laravel-apidoc-generator/pull/261)
+- Support for Laravel 5.5 auto-discovery (https://github.com/mpociot/laravel-apidoc-generator/pull/217)
+
+### Changed
+- Response calls are now only made when route is GET (https://github.com/mpociot/laravel-apidoc-generator/pull/279)
+- Validator factory is now passed to `FormRequest::validator` method (https://github.com/mpociot/laravel-apidoc-generator/pull/236)
+- Bind optional model parameters in routes (https://github.com/mpociot/laravel-apidoc-generator/pull/297/)
+- HEAD routes are no longer automatically generated for GET routes (https://github.com/mpociot/laravel-apidoc-generator/pull/180)
+- `actAsUserId` option is no longer cast to an int (https://github.com/mpociot/laravel-apidoc-generator/pull/257)
+
+### Fixed
+- `useMiddleware` option is now actually used (https://github.com/mpociot/laravel-apidoc-generator/pull/297/)
+- Changes to the info vendor view are now persisted (https://github.com/mpociot/laravel-apidoc-generator/pull/120)
+- Fixed memory leak issues (https://github.com/mpociot/laravel-apidoc-generator/pull/256)
+- Fixed issues with validating array parameters (https://github.com/mpociot/laravel-apidoc-generator/pull/299)
+- `@response` tag now parses content correctly as JSON (https://github.com/mpociot/laravel-apidoc-generator/pull/271)
+
+### Removed

+ 1 - 1
CONTRIBUTING.md

@@ -44,7 +44,7 @@ If the project maintainer has any additional requirements, you will find them li
 
 - **Add tests!** - Your patch won't be accepted if it doesn't have tests.
 
-- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
+- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. Add your changes to the `CHANGELOG.md` under the "Unreleased" section.
 
 - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
 

+ 10 - 9
README.md

@@ -4,13 +4,12 @@ Automatically generate your API documentation from your existing Laravel routes.
 
 `php artisan api:gen --routePrefix="settings/api/*"`
 
-![image](http://img.shields.io/packagist/v/mpociot/laravel-apidoc-generator.svg?style=flat)
-![image](http://img.shields.io/packagist/l/mpociot/laravel-apidoc-generator.svg?style=flat)
+[![Latest Stable Version](https://poser.pugx.org/mpociot/laravel-apidoc-generator/v/stable)](https://packagist.org/packages/mpociot/laravel-apidoc-generator)[![Total Downloads](https://poser.pugx.org/mpociot/laravel-apidoc-generator/downloads)](https://packagist.org/packages/mpociot/laravel-apidoc-generator)
+[![License](https://poser.pugx.org/mpociot/laravel-apidoc-generator/license)](https://packagist.org/packages/mpociot/laravel-apidoc-generator)
 [![codecov.io](https://codecov.io/github/mpociot/laravel-apidoc-generator/coverage.svg?branch=master)](https://codecov.io/github/mpociot/laravel-apidoc-generator?branch=master)
 [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/mpociot/laravel-apidoc-generator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/mpociot/laravel-apidoc-generator/?branch=master)
 [![Build Status](https://travis-ci.org/mpociot/laravel-apidoc-generator.svg?branch=master)](https://travis-ci.org/mpociot/laravel-apidoc-generator)
 [![StyleCI](https://styleci.io/repos/57999295/shield?style=flat)](https://styleci.io/repos/57999295)
-[![Dependency Status](https://www.versioneye.com/php/mpociot:laravel-apidoc-generator/dev-master/badge?style=flat)](https://www.versioneye.com/php/mpociot:laravel-apidoc-generator/dev-master)
 
 
 ## Installation
@@ -61,8 +60,9 @@ Route::group(array('prefix' => 'api/v1', 'middleware' => []), function () {
 Option | Description
 --------- | -------
 `output` | The output path used for the generated documentation. Default: `public/docs`
-`routePrefix` | The route prefix to use for generation - `*` can be used as a wildcard 
-`routes` | The route names to use for generation - Required if no routePrefix is provided
+`routePrefix` | The route prefix(es) to use for generation. `*` can be used as a wildcard. Multiple route prefixes can be specified by separating them with a comma (for instance `/v1,/v2`)
+`routeDomain` | The route domain(s) to use for generation. `*` can be used as a wildcard. Multiple route domains can be specified by separating them with a comma 
+`routes` | The route names to use for generation - Required if no routePrefix or routeDomain is provided
 `middleware` | The middlewares to use for generation
 `noResponseCalls` | Disable API response calls
 `noPostmanCollection` | Disable Postman collection creation
@@ -92,7 +92,7 @@ This package uses these resources to generate the API documentation:
 
 This package uses the HTTP controller doc blocks to create a table of contents and show descriptions for your API methods.
 
-Using `@resource` in a doc block prior to each controller is useful as it creates a Group within the API documentation for all methods defined in that controller (rather than listing every method in a single list for all your controllers), but using `@resource` is not required. The short description after the `@resource` should be unique to allow anchor tags to navigate to this section. A longer description can be included below.
+Using `@resource` in a doc block prior to each controller is useful as it creates a Group within the API documentation for all methods defined in that controller (rather than listing every method in a single list for all your controllers), but using `@resource` is not required. The short description after the `@resource` should be unique to allow anchor tags to navigate to this section. A longer description can be included below. Custom formatting and `<aside>` tags are also supported. (see the [Documentarian docs](http://marcelpociot.de/documentarian/installation/markdown_syntax))
 
 Above each method within the controller you wish to include in your API documentation you should have a doc block. This should include a unique short description as the first entry. An optional second entry can be added with further information. Both descriptions will appear in the API documentation in a different format as shown below.
 
@@ -176,13 +176,14 @@ public function transformerCollectionTag()
 The @transformermodel tag is needed for PHP 5.* to get the model. For PHP 7 is it optional to specify the model that is used for the transformer.
 
 #### @response
-If you expliciet want to specify the result of a function you can set it in the docblock
+If you explicitly want to specify the result of a function you can set it in the docblock as JSON, using the `@response` annotation:
 
 ```php
 /**
  * @response {
- *  data: [],
- *}
+ *  "token": "eyJ0eXAi…",
+ *  "roles": ["admin"]
+ * }
  */
 public function responseTag()
 {

+ 3 - 0
composer.json

@@ -38,6 +38,9 @@
             "Mpociot\\ApiDoc\\Tests\\": "tests/"
         }
     },
+    "scripts": {
+        "test-ci": "phpunit --coverage-clover=coverage.xml"
+    },
     "extra": {
         "laravel": {
             "providers": [

+ 4 - 4
src/Mpociot/ApiDoc/Commands/GenerateDocumentation.php

@@ -197,7 +197,7 @@ class GenerateDocumentation extends Command
 
         $documentarian->generate($outputPath);
 
-        $this->info('Wrote HTML documentation to: '.$outputPath.'/public/index.html');
+        $this->info('Wrote HTML documentation to: '.$outputPath.'/index.html');
 
         if ($this->option('noPostmanCollection') !== true) {
             $this->info('Generating Postman collection');
@@ -311,10 +311,10 @@ class GenerateDocumentation extends Command
                 || in_array($middleware, $route->middleware())
                ) {
                 if ($this->isValidRoute($route) && $this->isRouteVisibleForDocumentation($route->getAction()['uses'])) {
-                    $parsedRoutes[] = $generator->processRoute($route, $bindings, $this->option('header'), $withResponse);
-                    $this->info('Processed route: ['.implode(',', $route->getMethods()).'] '.$route->uri());
+                    $parsedRoutes[] = $generator->processRoute($route, $bindings, $this->option('header'), $withResponse && in_array('GET', $generator->getMethods($route)));
+                    $this->info('Processed route: ['.implode(',', $generator->getMethods($route)).'] '.$route->uri());
                 } else {
-                    $this->warn('Skipping route: ['.implode(',', $route->getMethods()).'] '.$route->uri());
+                    $this->warn('Skipping route: ['.implode(',', $generator->getMethods($route)).'] '.$route->uri());
                 }
             }
         }

+ 1 - 1
src/Mpociot/ApiDoc/Commands/UpdateDocumentation.php

@@ -53,6 +53,6 @@ class UpdateDocumentation extends Command
 
         $documentarian->generate($outputPath);
 
-        $this->info('Wrote HTML documentation to: '.$outputPath.'/public/index.html');
+        $this->info('Wrote HTML documentation to: '.$outputPath.'/index.html');
     }
 }

+ 20 - 13
src/Mpociot/ApiDoc/Generators/AbstractGenerator.php

@@ -11,6 +11,7 @@ use Mpociot\Reflection\DocBlock\Tag;
 use Illuminate\Support\Facades\Validator;
 use Illuminate\Foundation\Http\FormRequest;
 use Mpociot\ApiDoc\Parsers\RuleDescriptionParser as Description;
+use Illuminate\Contracts\Validation\Factory as ValidationFactory;
 
 abstract class AbstractGenerator
 {
@@ -86,9 +87,9 @@ abstract class AbstractGenerator
      */
     protected function getParameters($routeData, $routeAction, $bindings)
     {
-        $rules = $this->simplifyRules($this->getRouteRules($routeAction['uses'], $bindings));
+        $rules = $this->simplifyRules($this->getRouteRules($routeData['methods'], $routeAction['uses'], $bindings));
 
-        foreach ($rules as $attribute => $rules) {
+        foreach ($rules as $attribute => $ruleset) {
             $attributeData = [
                 'required' => false,
                 'type' => null,
@@ -96,8 +97,7 @@ abstract class AbstractGenerator
                 'value' => '',
                 'description' => [],
             ];
-
-            foreach ($rules as $ruleName => $rule) {
+            foreach ($ruleset as $rule) {
                 $this->parseRule($rule, $attribute, $attributeData, $routeData['id']);
             }
             $routeData['parameters'][$attribute] = $attributeData;
@@ -220,14 +220,15 @@ abstract class AbstractGenerator
     }
 
     /**
-     * @param  $route
+     * @param  array $routeMethods
+     * @param  string $routeAction
      * @param  array $bindings
      *
      * @return array
      */
-    protected function getRouteRules($route, $bindings)
+    protected function getRouteRules(array $routeMethods, $routeAction, $bindings)
     {
-        list($class, $method) = explode('@', $route);
+        list($class, $method) = explode('@', $routeAction);
         $reflection = new ReflectionClass($class);
         $reflectionMethod = $reflection->getMethod($method);
 
@@ -237,15 +238,21 @@ abstract class AbstractGenerator
                 $className = $parameterType->name;
 
                 if (is_subclass_of($className, FormRequest::class)) {
-                    $parameterReflection = new $className;
+                    /** @var FormRequest $formRequest */
+                    $formRequest = new $className;
                     // Add route parameter bindings
-                    $parameterReflection->query->add($bindings);
-                    $parameterReflection->request->add($bindings);
+                    $formRequest->setContainer(app());
+                    $formRequest->request->add($bindings);
+                    $formRequest->query->add($bindings);
+                    $formRequest->setMethod($routeMethods[0]);
+
+                    if (method_exists($formRequest, 'validator')) {
+                        $factory = app(ValidationFactory::class);
 
-                    if (method_exists($parameterReflection, 'validator')) {
-                        return $parameterReflection->validator()->getRules();
+                        return call_user_func_array([$formRequest, 'validator'], [$factory])
+                            ->getRules();
                     } else {
-                        return $parameterReflection->rules();
+                        return call_user_func_array([$formRequest, 'rules'], []);
                     }
                 }
             }

+ 0 - 41
src/Mpociot/ApiDoc/Generators/LaravelGenerator.php

@@ -10,8 +10,6 @@ use Illuminate\Support\Facades\App;
 use Mpociot\Reflection\DocBlock\Tag;
 use Illuminate\Support\Facades\Request;
 use League\Fractal\Resource\Collection;
-use Illuminate\Foundation\Http\FormRequest;
-use Illuminate\Contracts\Validation\Factory as ValidationFactory;
 
 class LaravelGenerator extends AbstractGenerator
 {
@@ -253,43 +251,4 @@ class LaravelGenerator extends AbstractGenerator
             return;
         }
     }
-
-    /**
-     * @param  string $route
-     * @param  array $bindings
-     *
-     * @return array
-     */
-    protected function getRouteRules($route, $bindings)
-    {
-        list($class, $method) = explode('@', $route);
-        $reflection = new ReflectionClass($class);
-        $reflectionMethod = $reflection->getMethod($method);
-
-        foreach ($reflectionMethod->getParameters() as $parameter) {
-            $parameterType = $parameter->getClass();
-            if (! is_null($parameterType) && class_exists($parameterType->name)) {
-                $className = $parameterType->name;
-
-                if (is_subclass_of($className, FormRequest::class)) {
-                    $parameterReflection = new $className;
-                    $parameterReflection->setContainer(app());
-                    // Add route parameter bindings
-                    $parameterReflection->query->add($bindings);
-                    $parameterReflection->request->add($bindings);
-
-                    if (method_exists($parameterReflection, 'validator')) {
-                        $factory = app()->make(ValidationFactory::class);
-
-                        return app()->call([$parameterReflection, 'validator'], [$factory])
-                            ->getRules();
-                    } else {
-                        return app()->call([$parameterReflection, 'rules']);
-                    }
-                }
-            }
-        }
-
-        return [];
-    }
 }

+ 2 - 2
src/resources/views/partials/route.blade.php

@@ -10,7 +10,7 @@
 > Example request:
 
 ```bash
-curl -X {{$parsedRoute['methods'][0]}} "{{config('app.docs_url') ?: config('app.url')}}/{{$parsedRoute['uri']}}" \
+curl -X {{$parsedRoute['methods'][0]}} "{{ trim(config('app.docs_url') ?: config('app.url'), '/')}}/{{ ltrim($parsedRoute['uri'], '/') }}" \
 -H "Accept: application/json"@if(count($parsedRoute['parameters'])) \
 @foreach($parsedRoute['parameters'] as $attribute => $parameter)
     -d "{{$attribute}}"="{{$parameter['value']}}" \
@@ -23,7 +23,7 @@ curl -X {{$parsedRoute['methods'][0]}} "{{config('app.docs_url') ?: config('app.
 var settings = {
     "async": true,
     "crossDomain": true,
-    "url": "{{config('app.docs_url') ?: config('app.url')}}/{{$parsedRoute['uri']}}",
+    "url": "{{ rtrim(config('app.docs_url') ?: config('app.url'), '/') }}/{{ ltrim($parsedRoute['uri'], '/') }}",
     "method": "{{$parsedRoute['methods'][0]}}",
     @if(count($parsedRoute['parameters']))
 "data": {!! str_replace('    ','        ',json_encode(array_combine(array_keys($parsedRoute['parameters']), array_map(function($param){ return $param['value']; },$parsedRoute['parameters'])), JSON_PRETTY_PRINT)) !!},

+ 1 - 1
tests/GenerateDocumentationTest.php

@@ -51,7 +51,7 @@ class GenerateDocumentationTest extends TestCase
     public function testConsoleCommandNeedsAPrefixOrRoute()
     {
         $output = $this->artisan('api:generate');
-        $this->assertEquals('You must provide either a route prefix or a route or a middleware to generate the documentation.'.PHP_EOL, $output);
+        $this->assertEquals('You must provide either a route prefix, a route domain, a route or a middleware to generate the documentation.'.PHP_EOL, $output);
     }
 
     public function testConsoleCommandDoesNotWorkWithClosure()