├── .lgtm ├── CODEOWNERS ├── .gitignore ├── config └── swaggerConfig.dist.php ├── PULL_REQUEST_TEMPLATE.md ├── bin └── swaggerize ├── ISSUE_TEMPLATE.md ├── tests ├── phpunit.xml └── OperationParser │ └── LumenControllerOperationParserTest.php ├── src ├── OperationParser │ ├── OperationParserInterface.php │ └── LumenControllerOperationParser.php ├── Command │ └── Scan.php └── functions.php ├── .circleci └── config.yml ├── composer.json ├── LICENSE.txt ├── LICENCE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── README.md /.lgtm: -------------------------------------------------------------------------------- 1 | approvals = 1 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @TidyMaze 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | composer.lock 4 | -------------------------------------------------------------------------------- /config/swaggerConfig.dist.php: -------------------------------------------------------------------------------- 1 | 'path/to/route/file', 5 | 'cacheEnabled' => true, 6 | 'namespace' => 'Iadvize\ServiceNamespace', 7 | ]; -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | What this PR does / why we need it: 2 | 3 | Which issue(s) this PR fixes (optional, in fixes #(, fixes #, ...) format, will close the issue(s) when PR gets merged): Fixes # -------------------------------------------------------------------------------- /bin/swaggerize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | add(new \Iadvize\SwaggerizeFastRoute\Command\Scan()); 7 | $app->run(); 8 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please answer these questions before submitting your issue. Thanks! 2 | 3 | ### What is your configuration, please give as much details as possible ? 4 | 5 | ### Does this issue reproduce with the latest release ? 6 | 7 | ### What did you do ? 8 | 9 | If possible, provide a recipe for reproducing the error. 10 | 11 | ### What did you expect to see ? 12 | 13 | ### What did you see instead ? 14 | -------------------------------------------------------------------------------- /tests/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | ./ 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/OperationParser/OperationParserInterface.php: -------------------------------------------------------------------------------- 1 | > /dev/null 12 | - run: 13 | name: Run phpunit 14 | command: ./vendor/bin/phpunit --configuration tests/phpunit.xml 15 | - run: 16 | name: Run phpcs 17 | command: ./vendor/bin/phpcs --standard=Iadvize src 18 | - run: 19 | name: Run phpmd 20 | command: ./vendor/bin/phpmd src text vendor/iadvize/php-convention/phpmd/phpmd.xml 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iadvize/php-swaggerize-fastroute-library", 3 | "description": "A library to automatically create FastRoute routes based on swagger JSON documentation", 4 | "authors": [ 5 | { 6 | "name": "Marc FRICOU", 7 | "email": "marc.fricou@iadvize.com" 8 | } 9 | ], 10 | "repositories": [ 11 | { 12 | "type": "git", 13 | "url": "git@github.com:iadvize/php-convention.git" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.5.21", 18 | "nikic/fast-route": "0.*", 19 | "thefrozenfire/swagger": "^2.0", 20 | "symfony/console": "^2.7" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "~4.8", 24 | "iadvize/php-convention": "dev-master", 25 | "mockery/mockery": "~0.9" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Iadvize\\SwaggerizeFastRoute\\": "src/", 30 | "IadvizeTest\\SwaggerizeFastRoute\\": "tests/" 31 | }, 32 | "files": ["src/functions.php"] 33 | }, 34 | "bin": [ 35 | "bin/swaggerize" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 iAdvize 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 iAdvize 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/OperationParser/LumenControllerOperationParser.php: -------------------------------------------------------------------------------- 1 | 'get', 21 | 'POST' => 'create', 22 | 'PUT' => 'update', 23 | 'HEAD' => 'head', 24 | 'OPTIONS' => 'options', 25 | 'PATCH' => 'patch', 26 | 'DELETE' => 'delete', 27 | ]; 28 | 29 | /** 30 | * Constructor 31 | * 32 | * @param string $controllerNamespace 33 | */ 34 | public function __construct($controllerNamespace) 35 | { 36 | if (substr('$controllerNamespace', -1) !== '\\') { 37 | $controllerNamespace .= '\\'; 38 | } 39 | 40 | $this->namespace = $controllerNamespace; 41 | } 42 | 43 | /** 44 | * Get Handler 45 | * 46 | * @param OperationReference $operation 47 | * 48 | * @return array 49 | */ 50 | public function getHandler(OperationReference $operation) 51 | { 52 | // remove route parameters 53 | $path = preg_replace('/\/\{.*\}/', '', $operation->getPath()); 54 | 55 | // lowerCamelCase to UpperCamelCase 56 | $paths = explode('/', $path); 57 | // path start with a / 58 | unset($paths[0]); 59 | $paths = array_map(function ($path) { 60 | return ucfirst($path); 61 | }, $paths); 62 | // path to 'relative' namespace 63 | $path = implode('\\', $paths); 64 | 65 | $controller = $this->namespace . $path . 'Controller'; 66 | 67 | return ['uses' => $controller . '@' . $this->httpVerbToControllerMethod[strtoupper($operation->getMethod())], 'as' => $operation->getOperationId()]; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Command/Scan.php: -------------------------------------------------------------------------------- 1 | setName('swagger:scan') 26 | ->setDescription('Scan swagger JSON file ') 27 | ->addArgument( 28 | 'swaggerFile', 29 | InputArgument::REQUIRED, 30 | 'Give JSON file to scan' 31 | ) 32 | ->addArgument( 33 | 'controllerNamespace', 34 | InputArgument::REQUIRED, 35 | 'Controllers namespace that will handle route' 36 | ) 37 | ->addOption( 38 | 'routeFile', 39 | null, 40 | InputOption::VALUE_REQUIRED, 41 | 'Where FastRoute cache file should be write ? Default to output' 42 | ); 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | protected function execute(InputInterface $input, OutputInterface $output) 49 | { 50 | $controllerNamespace = $input->getArgument('controllerNamespace'); 51 | $swaggerFile = $input->getArgument('swaggerFile'); 52 | $routeStream = $input->getOption('routeFile'); 53 | 54 | if (!$routeStream) { 55 | $routeStream = 'php://output'; 56 | } 57 | 58 | $operationParser = new LumenControllerOperationParser($controllerNamespace); 59 | 60 | $routes = \Iadvize\SwaggerizeFastRoute\scan($swaggerFile, $operationParser); 61 | 62 | \Iadvize\SwaggerizeFastRoute\cacheRoutes($routes, $routeStream); 63 | 64 | if ($routeStream !== 'php://output') { 65 | $output->writeln('route file available at ' . $routeStream); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/OperationParser/LumenControllerOperationParserTest.php: -------------------------------------------------------------------------------- 1 | operationParser = new LumenControllerOperationParser('Iadvize\Test'); 24 | } 25 | 26 | /** 27 | * Test: Get handler should return an Lumen compatible Array with controller@method 28 | */ 29 | public function testGetHandler() 30 | { 31 | $operationMock = \Mockery::mock(OperationReference::class); 32 | $operationMock->shouldReceive('getPath')->andReturn('/marco'); 33 | $operationMock->shouldReceive('getMethod')->andReturn('GET'); 34 | $operationMock->shouldReceive('getOperationId')->andReturn('operationID'); 35 | 36 | $this->assertEquals(['uses' => 'Iadvize\Test\MarcoController@get', 'as' => 'operationID'], $this->operationParser->getHandler($operationMock)); 37 | } 38 | 39 | /** 40 | * Test: Get handler should return an Lumen compatible Array with controller@method 41 | */ 42 | public function testGetHandlerWithRouteParameter() 43 | { 44 | $operationMock = \Mockery::mock(OperationReference::class); 45 | $operationMock->shouldReceive('getPath')->andReturn('/marco/{id}'); 46 | $operationMock->shouldReceive('getMethod')->andReturn('PUT'); 47 | $operationMock->shouldReceive('getOperationId')->andReturn('operationID'); 48 | 49 | $this->assertEquals(['uses' => 'Iadvize\Test\MarcoController@update', 'as' => 'operationID'], $this->operationParser->getHandler($operationMock)); 50 | } 51 | 52 | /** 53 | * Test: Get handler should return an Lumen compatible Array with controller@method 54 | */ 55 | public function testGetHandlerWithDeepPath() 56 | { 57 | $operationMock = \Mockery::mock(OperationReference::class); 58 | $operationMock->shouldReceive('getPath')->andReturn('/marco/{id}/name/first'); 59 | $operationMock->shouldReceive('getMethod')->andReturn('POST'); 60 | $operationMock->shouldReceive('getOperationId')->andReturn('operationID'); 61 | 62 | $this->assertEquals(['uses' => 'Iadvize\Test\Marco\Name\FirstController@create', 'as' => 'operationID'], $this->operationParser->getHandler($operationMock)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/functions.php: -------------------------------------------------------------------------------- 1 | getOperationsById(); 38 | 39 | $routes = []; 40 | 41 | foreach ($operations as $operation) { 42 | $routes[] = [ 43 | 'method' => $operation->getMethod(), 44 | 'uri' => $operation->getPath(), 45 | 'action' => $operationParser->getHandler($operation), 46 | ]; 47 | } 48 | 49 | return $routes; 50 | } 51 | 52 | /** 53 | * Add route to route collector 54 | * 55 | * @param string $swaggerJson Swagger json file path (can be an URL) 56 | * @param RouteCollector $routeCollector FastRoute route collector 57 | * @param OperationParserInterface $operationParser Swagger operation parser. 58 | * @param array $options Options (@see config/swaggerConfig.dist.php) 59 | */ 60 | function addRoutes($swaggerJson, RouteCollector $routeCollector, OperationParserInterface $operationParser, $options = []) 61 | { 62 | if (!isset($options['routeFile']) || !file_exists($options['routeFile'])) { 63 | $routes = scan($swaggerJson, $operationParser); 64 | } else { 65 | $routes = require $options['routeFile']; 66 | } 67 | 68 | if (isset($options['routeFile']) && isset($options['cacheEnabled']) && $options['cacheEnabled']) { 69 | cacheRoutes($routes, $options['routeFile']); 70 | } 71 | 72 | foreach ($routes as $route) { 73 | $routeCollector->addRoute($route['method'], $route['uri'], $route['action']); 74 | } 75 | } 76 | 77 | /** 78 | * Write routes array into a file 79 | * 80 | * @param array $routes Routes 81 | * @param string $stream File name or stream in which write routes. 82 | */ 83 | function cacheRoutes(array $routes, $stream) 84 | { 85 | if (is_writable($stream)) { 86 | throw new \LogicException($stream . ' is not writable'); 87 | } 88 | 89 | $routeResource = fopen($stream, 'w'); 90 | 91 | $serializedRoutes = var_export($routes, true); 92 | 93 | fwrite($routeResource, ' 25 | ## Bug reports 26 | 27 | A bug is a _demonstrable problem_ that is caused by the code in the repository. 28 | Good bug reports are extremely helpful - thank you! 29 | 30 | Guidelines for bug reports: 31 | 32 | 1. **Use the GitHub issue search** — check if the issue has already been 33 | reported. 34 | 35 | 2. **Check if the issue has been fixed** — try to reproduce it using the 36 | latest `master` or development branch in the repository. 37 | 38 | 3. **Isolate the problem** — make sure that the code in the repository is 39 | _definitely_ responsible for the issue. 40 | 41 | A good bug report shouldn't leave others needing to chase you up for more 42 | information. Please try to be as detailed as possible in your report. 43 | 44 | 45 | 46 | ## Feature requests 47 | 48 | Feature requests are welcome. But take a moment to find out whether your idea 49 | fits with the scope and aims of the project. It's up to *you* to make a strong 50 | case to convince the Roots developers of the merits of this feature. Please 51 | provide as much detail and context as possible. 52 | 53 | 54 | 55 | ## Pull requests 56 | 57 | Good pull requests - patches, improvements, new features - are a fantastic 58 | help. They should remain focused in scope and avoid containing unrelated 59 | commits. 60 | 61 | **Please ask first** before embarking on any significant pull request (e.g. 62 | implementing features, refactoring code), otherwise you risk spending a lot of 63 | time working on something that the developers might not want to merge into the 64 | project. 65 | 66 | Please adhere to the coding conventions used throughout the project (indentation, 67 | comments, etc.). 68 | 69 | Adhering to the following this process is the best way to get your work 70 | merged: 71 | 72 | 1. [Fork](http://help.github.com/fork-a-repo/) the repo, clone your fork, 73 | and configure the remotes: 74 | 75 | ```bash 76 | # Clone your fork of the repo into the current directory 77 | git clone https://github.com// 78 | # Navigate to the newly cloned directory 79 | cd 80 | # Assign the original repo to a remote called "upstream" 81 | git remote add upstream https://github.com// 82 | ``` 83 | 84 | 2. If you cloned a while ago, get the latest changes from upstream: 85 | 86 | ```bash 87 | git checkout 88 | git pull upstream 89 | ``` 90 | 91 | 3. Create a new topic branch (off the main project development branch) to 92 | contain your feature, change, or fix: 93 | 94 | ```bash 95 | git checkout -b 96 | ``` 97 | 98 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 99 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 100 | or your code is unlikely be merged into the main project. Use Git's 101 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 102 | feature to tidy up your commits before making them public. 103 | 104 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 105 | 106 | ```bash 107 | git pull [--rebase] upstream 108 | ``` 109 | 110 | 6. Push your topic branch up to your fork: 111 | 112 | ```bash 113 | git push origin 114 | ``` 115 | 116 | 10. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 117 | with a clear title and description. 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | php-swaggerize-fastroute-library [![CircleCI](https://circleci.com/gh/iadvize/php-swaggerize-fastroute-library.svg?style=svg)](https://circleci.com/gh/iadvize/php-swaggerize-fastroute-library) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/iadvize/php-swaggerize-fastroute-library/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/iadvize/php-swaggerize-fastroute-library/?branch=master) 2 | ================================= 3 | 4 | > **⚠️ WARNING**: This repository is deprecated and no longer maintained since 2015. See removal guide [here](#removal-guide). 5 | 6 | A library to automatically create FastRoute routes based on swagger JSON documentation 7 | 8 | ## Removal guide 9 | 10 | This library is deprecated and no longer maintained since 2015. Here is a guide to remove it from your project: 11 | 12 | - check that your app uses this library `iadvize/php-swaggerize-fastroute-library` (search for `Iadvize\SwaggerizeFastRoute` package import in php code). If it does not, you can safely remove it from your `composer.json` and skip the next steps. 13 | - if your CI/CD or dockerfile uses the `swaggerize swagger:scan` command, you should: 14 | - run it manually once (use your full existing command, eg: `./vendor/bin/swaggerize swagger:scan storage/docs/definition.json "path/to/controllers" --routeFile somewhere/routeFile.php`) 15 | - remove the `swaggerize swagger:scan` command from your CI/CD or dockerfile 16 | - convert the generated route file to a standard FastRoute setup (see [FastRoute documentation](https://github.com/nikic/FastRoute?tab=readme-ov-file#usage)), usually the same file as the one using the `Iadvize\SwaggerizeFastRoute` package. 17 | - remove the `Iadvize\SwaggerizeFastRoute` package import from your php code and all usage. 18 | - remove the `iadvize/php-swaggerize-fastroute-library` from your `composer.json` (eg: `composer remove iadvize/php-swaggerize-fastroute-library`) 19 | - delete the routeFile.php file (not needed anymore) 20 | 21 | ## Examples 22 | 23 | ### Generate route File (FastRoute compatible) 24 | 25 | ``` 26 | vendor/bin/swaggerize swagger:scan path/to/swagger/json controllers\namespace [--routeFile=route/file/path] 27 | ``` 28 | 29 | ## Install 30 | 31 | To install with composer: 32 | ``` 33 | composer require iadvize/php-swaggerize-fastroute-library 34 | ``` 35 | 36 | ## Documentation 37 | 38 | ### Generate route File (FastRoute compatible) 39 | 40 | ``` 41 | vendor/bin/swaggerize swagger:scan path/to/swagger/json controllers\namespace [--routeFile=route/file/path] 42 | ``` 43 | 44 | ### Dispatch generated file or simply use cache 45 | 46 | You can then use FastRoute cached dispatcher to use generated file or directly use a cache dispatcher (file will be generated at first call). 47 | 48 | ```PHP 49 | 'route/file/path']) { 56 | \Iadvize\SwaggerizeFastRoute\addRoutes( 57 | 'path/to/swagger/json', 58 | $r, 59 | $lumenOperationParser, 60 | ['routeFile' => 'path/to/generated/route/file', 'cacheEnabled' => false] 61 | ); 62 | }); 63 | 64 | // Fetch method and URI from somewhere 65 | // ... see FastRoute Dispatcher 66 | ``` 67 | 68 | Alternatively to generate routes, you can simply cache first parse by setting `'cacheEnabled' => true` in addRoute function. 69 | 70 | ### Apply this to Lumen application 71 | 72 | To use this swagger routes in a Lumen Application (which use FastRoute as route library), you need to extends `Laravel\Lumen\Application` and override `createDispatcher` method. 73 | 74 | ```PHP 75 | 76 | dispatcher ?: \FastRoute\simpleDispatcher(function ($r) { 95 | foreach ($this->routes as $route) { 96 | $r->addRoute($route['method'], $route['uri'], $route['action']); 97 | } 98 | 99 | $operationParser = new \Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser('My\Application\Http\Controllers'); 100 | 101 | \Iadvize\SwaggerizeFastRoute\addRoutes(storage_path('docs/definition.json'), $r, $operationParser, ['routeFile' => 'route/file/path']); 102 | }); 103 | } 104 | } 105 | ``` 106 | 107 | ### How handler is formed 108 | 109 | Handlers are formed from route defined in swagger as [Lumen](http://lumen.laravel.com/docs/routing#named-routes) define it for controller class : `Controller@method` 110 | 111 | #### Controller class generation 112 | 113 | Controller class is determined from path route with first character uppercased and with Controller at the end of file name 114 | 115 | This swagger JSON : 116 | 117 | ```JSON 118 | { 119 | // ... 120 | "paths": { 121 | "/pets": { 122 | "get": { 123 | // ... 124 | } 125 | "put": { 126 | // ... 127 | } 128 | } 129 | "/store": { 130 | "post": { 131 | // ... 132 | } 133 | } 134 | } 135 | // ... 136 | } 137 | ``` 138 | 139 | will generates respectively this handlers: 140 | 141 | * `PetsController@get` 142 | * `PetsController@update` 143 | * `StoreController@create` 144 | 145 | #### Method generation 146 | 147 | Controller method is mapped from HTTP method : 148 | * `GET` => `get`, 149 | * `POST` => `create`, 150 | * `PUT` => `update`, 151 | * `HEAD` => `head`, 152 | * `OPTIONS` => `options`, 153 | * `PATCH` => `patch`, 154 | * `DELETE` => `delete`, 155 | 156 | ## Contribute 157 | 158 | Look at contribution guidelines here : [CONTRIBUTING.md](CONTRIBUTING.md) 159 | --------------------------------------------------------------------------------