From c473a55695333d641cf9157dfaaf646668327c68 Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Tue, 20 Oct 2015 10:28:56 +0200 Subject: [PATCH 01/10] feat: init --- .gitignore | 3 +++ composer.json | 42 ++++++++++++++++++++++++++++++++++++++++++ tests/phpunit.xml | 15 +++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 tests/phpunit.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f38912 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +vendor +composer.lock diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..5b4b00c --- /dev/null +++ b/composer.json @@ -0,0 +1,42 @@ +{ + "name": "iadvize/php-swaggerize-fastroute-library", + "description": "A library to automatically create FastRoute routes based on swagger JSON documentation", + "authors": [ + { + "name": "Marc FRICOU", + "email": "marc.fricou@iadvize.com" + } + ], + + "repositories": [ + { + "type": "git", + "url": "git@github.com:iadvize/lumen-doctrine.git" + }, + { + "type": "git", + "url": "git@github.com:iadvize/api-swagger-ui.git" + }, + { + "type": "git", + "url": "git@github.com:iadvize/standards.git" + } + ], + "require": { + "php": ">=5.5.21", + "nikic/fast-route": "0.*", + "thefrozenfire/swagger": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8", + "iadvize/standards": "dev-moveComposer", + "mockery/mockery": "~0.9" + }, + "autoload": { + "psr-4": { + "Iadvize\\SwaggerizeFastRoute\\": "src/", + "IadvizeTest\\SwaggerizeFastRoute\\": "tests/" + }, + "files": ["src/functions.php"] + } +} diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 0000000..c8c336f --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,15 @@ + + + + + ./ + + + From 41344856c23bdfcc57b35c692984f35c88f11f68 Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Tue, 20 Oct 2015 10:29:18 +0200 Subject: [PATCH 02/10] feat(scan): basic scan --- README.md | 122 ++++++++++++++++++ .../LumenControllerOperationParser.php | 69 ++++++++++ .../OperationParserInterface.php | 22 ++++ src/functions.php | 31 +++++ .../LumenControllerOperationParserTest.php | 64 +++++++++ 5 files changed, 308 insertions(+) create mode 100644 src/OperationParser/LumenControllerOperationParser.php create mode 100644 src/OperationParser/OperationParserInterface.php create mode 100644 src/functions.php create mode 100644 tests/OperationParser/LumenControllerOperationParserTest.php diff --git a/README.md b/README.md index a8f27b4..bd2f4e8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,124 @@ # php-swaggerize-fastroute-library A library to automatically create FastRoute routes based on swagger JSON documentation +# Install +To install with composer: +``` +composer require iadvize/php-swaggerize-fastroute-library +``` +# Dispatch swagger app + +``` +dispatch($httpMethod, $uri); +switch ($routeInfo[0]) { + case FastRoute\Dispatcher::NOT_FOUND: + // ... 404 Not Found + break; + case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: + $allowedMethods = $routeInfo[1]; + // ... 405 Method Not Allowed + break; + case FastRoute\Dispatcher::FOUND: + $handler = $routeInfo[1]; + $vars = $routeInfo[2]; + // ... call $handler with $vars + break; +} +``` +# Use a cache dispatcher + +Parse swagger JSON and create route dynamically at each API call can be heavy. If you need performance, use FastRoute cachedDispatcher + +``` + 'path/to/cache/file']) { + \Iadvize\SwaggerizeFastRoute\scan('https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', $r, $lumenOperationParser); +}); + +// Fetch method and URI from somewhere +$httpMethod = $_SERVER['REQUEST_METHOD']; +$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); + +$routeInfo = $dispatcher->dispatch($httpMethod, $uri); +switch ($routeInfo[0]) { + case FastRoute\Dispatcher::NOT_FOUND: + // ... 404 Not Found + break; + case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: + $allowedMethods = $routeInfo[1]; + // ... 405 Method Not Allowed + break; + case FastRoute\Dispatcher::FOUND: + $handler = $routeInfo[1]; + $vars = $routeInfo[2]; + // ... call $handler with $vars + break; +} +``` + +# How handler is formed + +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` +### Controller class generation + +Controller class is determined from path route with first character uppercased and with Controller at the end of file name + +This swagger JSON : + +```JSON +{ +// ... + "paths": { + "/pets": { + "get": { + // ... + } + "put": { + // ... + } + } + "/store": { + "post": { + // ... + } + } + } +// ... +} +``` + +will generates respectively this handlers: + +* `PetsController@get` +* `PetsController@update` +* `StoreController@create` + +### Method generation + +Controller method is mapped from HTTP method : +* `GET` => `get`, +* `POST` => `create`, +* `PUT` => `update`, +* `HEAD` => `head`, +* `OPTIONS` => `options`, +* `PATCH` => `patch`, +* `DELETE` => `delete`, + diff --git a/src/OperationParser/LumenControllerOperationParser.php b/src/OperationParser/LumenControllerOperationParser.php new file mode 100644 index 0000000..b2a4a0f --- /dev/null +++ b/src/OperationParser/LumenControllerOperationParser.php @@ -0,0 +1,69 @@ + 'get', + 'POST' => 'create', + 'PUT' => 'update', + 'HEAD' => 'head', + 'OPTIONS' => 'options', + 'PATCH' => 'patch', + 'DELETE' => 'delete', + ]; + + /** + * Constructor + * + * @param string $controllerNamespace + */ + public function __construct($controllerNamespace) + { + if (strpos($controllerNamespace, '\\') === strlen($controllerNamespace) - 1) { + $controllerNamespace = mb_substr($controllerNamespace, 0, -1); + } + + $this->namespace = $controllerNamespace; + } + + /** + * Get Handler + * + * @param OperationReference $operation + * + * @return array + */ + public function getHandler(OperationReference $operation) + { + // remove route parameters + $path = preg_replace('/\/\{.*\}/', '', $operation->getPath()); + + // lowerCamelCase to UpperCamelCase + $paths = explode('/', $path); + // path start with a / + unset($paths[0]); + foreach ($paths as &$path) { + $path[0] = strtoupper($path[0]); + } + // path to 'relative' namespace + $path = implode('\\', $paths); + + $controller = $this->namespace . $path . 'Controller'; + + return ['uses' => $controller . '@' . $this->httpVerbToControllerMethod[strtoupper($operation->getMethod())], 'as' => $operation->getOperationId()]; + } +} diff --git a/src/OperationParser/OperationParserInterface.php b/src/OperationParser/OperationParserInterface.php new file mode 100644 index 0000000..a7a0949 --- /dev/null +++ b/src/OperationParser/OperationParserInterface.php @@ -0,0 +1,22 @@ +getOperationsById(); + + foreach ($operations as $operation) { + $routeCollector->addRoute($operation->getMethod(), $operation->getPath(), $operationParser->getHandler($operation)); + } +} diff --git a/tests/OperationParser/LumenControllerOperationParserTest.php b/tests/OperationParser/LumenControllerOperationParserTest.php new file mode 100644 index 0000000..9d4a54e --- /dev/null +++ b/tests/OperationParser/LumenControllerOperationParserTest.php @@ -0,0 +1,64 @@ +operationParser = new LumenControllerOperationParser('Iadvize\Test\\'); + } + + /** + * Test: Get handler should return an Lumen compatible Array with controller@method + */ + public function testGetHandler() + { + $operationMock = \Mockery::mock(OperationReference::class); + $operationMock->shouldReceive('getPath')->andReturn('/marco'); + $operationMock->shouldReceive('getMethod')->andReturn('GET'); + $operationMock->shouldReceive('getOperationId')->andReturn('operationID'); + + $this->assertEquals(['uses' => 'Iadvize\Test\MarcoController@get', 'as' => 'operationID'], $this->operationParser->getHandler($operationMock)); + } + + /** + * Test: Get handler should return an Lumen compatible Array with controller@method + */ + public function testGetHandlerWithRouteParameter() + { + $operationMock = \Mockery::mock(OperationReference::class); + $operationMock->shouldReceive('getPath')->andReturn('/marco/{id}'); + $operationMock->shouldReceive('getMethod')->andReturn('PUT'); + $operationMock->shouldReceive('getOperationId')->andReturn('operationID'); + + $this->assertEquals(['uses' => 'Iadvize\Test\MarcoController@update', 'as' => 'operationID'], $this->operationParser->getHandler($operationMock)); + } + + /** + * Test: Get handler should return an Lumen compatible Array with controller@method + */ + public function testGetHandlerWithDeepPath() + { + $operationMock = \Mockery::mock(OperationReference::class); + $operationMock->shouldReceive('getPath')->andReturn('/marco/{id}/name/first'); + $operationMock->shouldReceive('getMethod')->andReturn('POST'); + $operationMock->shouldReceive('getOperationId')->andReturn('operationID'); + + $this->assertEquals(['uses' => 'Iadvize\Test\Marco\Name\FirstController@create', 'as' => 'operationID'], $this->operationParser->getHandler($operationMock)); + } +} From b22592cd424636239ec1db728d3d8cba4dc2fd31 Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Tue, 20 Oct 2015 11:15:01 +0200 Subject: [PATCH 03/10] doc: readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd2f4e8..45e5982 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ composer require iadvize/php-swaggerize-fastroute-library ``` # Dispatch swagger app -``` +```PHP Date: Tue, 20 Oct 2015 15:52:00 +0200 Subject: [PATCH 04/10] feat(console): add command to generate cached file --- README.md | 55 +++++++++++++++++++++++++--- bin/swaggerize | 7 ++++ cache.php | 42 ++++++++++++++++++++++ composer.json | 8 +++-- config/swaggerConfig.dist.php | 7 ++++ src/Command/Scan.php | 67 +++++++++++++++++++++++++++++++++++ src/functions.php | 63 ++++++++++++++++++++++++++++++-- 7 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 bin/swaggerize create mode 100644 cache.php create mode 100644 config/swaggerConfig.dist.php create mode 100644 src/Command/Scan.php diff --git a/README.md b/README.md index 45e5982..a489ac0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,16 @@ To install with composer: ``` composer require iadvize/php-swaggerize-fastroute-library ``` -# Dispatch swagger app + +# Generate route File (FastRoute compatible) + +``` +vendor/bin/swaggerize swagger:scan path/to/swagger/json controllers\namespace [--routeFile=route/file/path] +``` + +# Dispatch generated file + +You can then use FastRoute cached dispatcher to use generated file or directly use a cache dispatcher (file will be generated at first call). ```PHP 'route/file/path']) { \Iadvize\SwaggerizeFastRoute\scan('https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', $r, $lumenOperationParser); }); @@ -38,9 +47,8 @@ switch ($routeInfo[0]) { break; } ``` -# Use a cache dispatcher -Parse swagger JSON and create route dynamically at each API call can be heavy. If you need performance, use FastRoute cachedDispatcher +# Directly dispatch swagger app ```PHP 'path/to/cache/file']) { +$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) { \Iadvize\SwaggerizeFastRoute\scan('https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', $r, $lumenOperationParser); }); @@ -74,6 +82,43 @@ switch ($routeInfo[0]) { } ``` +# Apply this to Lumen application + +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` class. + +```PHP + +dispatcher ?: \FastRoute\simpleDispatcher(function ($r) { + foreach ($this->routes as $route) { + $r->addRoute($route['method'], $route['uri'], $route['action']); + } + + $operationParser = new \Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser('My\Application\Http\Controllers'); + + \Iadvize\SwaggerizeFastRoute\addRoutes(storage_path('docs/definition.json'), $r, $operationParser, ['routeFile' => 'route/file/path']); + }); + } +} + + # How handler is formed 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` diff --git a/bin/swaggerize b/bin/swaggerize new file mode 100644 index 0000000..0189794 --- /dev/null +++ b/bin/swaggerize @@ -0,0 +1,7 @@ +#!/usr/bin/env php +add(new \Iadvize\SwaggerizeFastRoute\Command\Scan()); +$app->run(); diff --git a/cache.php b/cache.php new file mode 100644 index 0000000..32eea0d --- /dev/null +++ b/cache.php @@ -0,0 +1,42 @@ + + array ( + 'method' => 'POST', + 'uri' => '/button', + 'action' => + array ( + 'uses' => 'IadvizeTargetingApiServiceButtonController@create', + 'as' => 'createButton', + ), + ), + 1 => + array ( + 'method' => 'POST', + 'uri' => '/invitation', + 'action' => + array ( + 'uses' => 'IadvizeTargetingApiServiceInvitationController@create', + 'as' => 'createInvitation', + ), + ), + 2 => + array ( + 'method' => 'POST', + 'uri' => '/targetingRule', + 'action' => + array ( + 'uses' => 'IadvizeTargetingApiServiceTargetingRuleController@create', + 'as' => 'createTargetingRule', + ), + ), + 3 => + array ( + 'method' => 'POST', + 'uri' => '/visitorAttribute', + 'action' => + array ( + 'uses' => 'IadvizeTargetingApiServiceVisitorAttributeController@create', + 'as' => 'createVisitorAttribute', + ), + ), +); \ No newline at end of file diff --git a/composer.json b/composer.json index 5b4b00c..86ed8d8 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "require-dev": { "phpunit/phpunit": "~4.8", "iadvize/standards": "dev-moveComposer", - "mockery/mockery": "~0.9" + "mockery/mockery": "~0.9", + "symfony/console": "^2.7" }, "autoload": { "psr-4": { @@ -38,5 +39,8 @@ "IadvizeTest\\SwaggerizeFastRoute\\": "tests/" }, "files": ["src/functions.php"] - } + }, + "bin": [ + "bin/swaggerize" + ] } diff --git a/config/swaggerConfig.dist.php b/config/swaggerConfig.dist.php new file mode 100644 index 0000000..b1f34f8 --- /dev/null +++ b/config/swaggerConfig.dist.php @@ -0,0 +1,7 @@ + 'path/to/route/file', + 'cacheEnabled' => true, + 'namespace' => 'Iadvize\ServiceNamespace', +]; \ No newline at end of file diff --git a/src/Command/Scan.php b/src/Command/Scan.php new file mode 100644 index 0000000..6b75cf5 --- /dev/null +++ b/src/Command/Scan.php @@ -0,0 +1,67 @@ +setName('swagger:scan') + ->setDescription('Scan swagger JSON file ') + ->addArgument( + 'swaggerFile', + InputArgument::REQUIRED, + 'Give JSON file to scan' + ) + ->addArgument( + 'controllerNamespace', + InputArgument::REQUIRED, + 'Controllers namespace that will handle route' + ) + ->addOption( + 'routeFile', + null, + InputOption::VALUE_REQUIRED, + 'Where FastRoute cache file should be write ? Default to output' + ); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $controllerNamespace = $input->getArgument('controllerNamespace'); + $swaggerFile = $input->getArgument('swaggerFile'); + $routeStream = $input->getOption('routeFile'); + + if (!$routeStream) { + $routeStream = 'php://output'; + } + + $operationParser = new \Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser($controllerNamespace); + + $routes = \Iadvize\SwaggerizeFastRoute\scan($swaggerFile, $operationParser); + + \Iadvize\SwaggerizeFastRoute\cacheRoutes($routes, $routeStream); + + if ($routeStream !== 'php://output') { + $output->writeln('route file available at ' . $routeStream); + } + } +} diff --git a/src/functions.php b/src/functions.php index 51f75b9..6cb6810 100644 --- a/src/functions.php +++ b/src/functions.php @@ -11,21 +11,78 @@ * Scan the json file and build routes * * @param string $file The file path - * @param RouteCollector $routeCollector Route collector * @param OperationParserInterface $operationParser Operation parser + * + * @return array */ -function scan($file, RouteCollector $routeCollector, OperationParserInterface $operationParser) +function scan($file, OperationParserInterface $operationParser) { $json = file_get_contents($file); + if (!$json) { + throw new \LogicException($file . ' can not be read'); + } + $swagger = json_decode($json); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \LogicException($file . ' is not a valid json file'); + } + $document = new Document($swagger); /** @var OperationReference[] $operations */ $operations = $document->getOperationsById(); + $routes = []; + foreach ($operations as $operation) { - $routeCollector->addRoute($operation->getMethod(), $operation->getPath(), $operationParser->getHandler($operation)); + $routes[] = [ + 'method' => $operation->getMethod(), + 'uri' => $operation->getPath(), + 'action' => $operationParser->getHandler($operation), + ]; + } + + return $routes; +} + +/** + * Add route to route collector + * + * @param string $swaggerJson Swagger json file path (can be an URL) + * @param RouteCollector $routeCollector FastRoute route collector + * @param OperationParserInterface $operationParser Swagger operation parser. + * @param array $options Options (@see config/swaggerConfig.dist.php) + */ +function addRoutes($swaggerJson, RouteCollector $routeCollector, OperationParserInterface $operationParser, $options = []) +{ + if (!isset($options['routeFile']) || !file_exists($options['routeFile'])) { + $routes = scan($swaggerJson, $operationParser); + } else { + $routes = require $options['routeFile']; + } + + if (isset($options['routeFile']) && isset($options['cacheEnabled']) && $options['cacheEnabled']) { + cacheRoutes($routes, $options['routeFile']); } + + foreach ($routes as $route) { + $routeCollector->addRoute($route['method'], $route['uri'], $route['action']); + } +} + +/** + * Write routes array into a file + * + * @param array $routes Routes + * @param string $stream File name or stream in which write routes. + */ +function cacheRoutes(array $routes, $stream) +{ + $routeResource = fopen($stream, 'w'); + + $serializedRoutes = var_export($routes, true); + + fwrite($routeResource, ' Date: Tue, 20 Oct 2015 16:01:34 +0200 Subject: [PATCH 05/10] doc: better readme --- README.md | 55 +++++++++++++++++++------------------------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index a489ac0..b388bdb 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ composer require iadvize/php-swaggerize-fastroute-library vendor/bin/swaggerize swagger:scan path/to/swagger/json controllers\namespace [--routeFile=route/file/path] ``` -# Dispatch generated file +# Dispatch generated file or simply use cache You can then use FastRoute cached dispatcher to use generated file or directly use a cache dispatcher (file will be generated at first call). @@ -24,42 +24,25 @@ require '/path/to/vendor/autoload.php'; $lumenOperationParser = new \Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser('Controllers\\Namespace\\'); $dispatcher = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r, ['cacheFile' => 'route/file/path']) { - \Iadvize\SwaggerizeFastRoute\scan('https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', $r, $lumenOperationParser); + \Iadvize\SwaggerizeFastRoute\addRoutes( + 'https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', + $r, + $lumenOperationParser, + ['routeFile' => 'path/to/generated/route/file'] + ); }); -// Fetch method and URI from somewhere -$httpMethod = $_SERVER['REQUEST_METHOD']; -$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); - -$routeInfo = $dispatcher->dispatch($httpMethod, $uri); -switch ($routeInfo[0]) { - case FastRoute\Dispatcher::NOT_FOUND: - // ... 404 Not Found - break; - case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: - $allowedMethods = $routeInfo[1]; - // ... 405 Method Not Allowed - break; - case FastRoute\Dispatcher::FOUND: - $handler = $routeInfo[1]; - $vars = $routeInfo[2]; - // ... call $handler with $vars - break; -} -``` - -# Directly dispatch swagger app - -```PHP - 'route/file/path']) { + \Iadvize\SwaggerizeFastRoute\addRoutes( + 'https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', + $r, + $lumenOperationParser, + ['routeFile' => 'path/to/generated/route/file', 'cacheEnabled' => true] + ); }); +*/ // Fetch method and URI from somewhere $httpMethod = $_SERVER['REQUEST_METHOD']; @@ -84,7 +67,7 @@ switch ($routeInfo[0]) { # Apply this to Lumen application -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` class. +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. ```PHP @@ -117,7 +100,7 @@ class Application extends LumenApplication }); } } - +``` # How handler is formed From 11f998782bddd1be9309d2c2dddc3c742c5f396c Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Tue, 20 Oct 2015 16:52:44 +0200 Subject: [PATCH 06/10] =?UTF-8?q?fix(op=C3=A9ration=20passer):=20last=20\?= =?UTF-8?q?=20namespace=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/OperationParser/LumenControllerOperationParser.php | 4 ++-- tests/OperationParser/LumenControllerOperationParserTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OperationParser/LumenControllerOperationParser.php b/src/OperationParser/LumenControllerOperationParser.php index b2a4a0f..0790a9c 100644 --- a/src/OperationParser/LumenControllerOperationParser.php +++ b/src/OperationParser/LumenControllerOperationParser.php @@ -33,8 +33,8 @@ class LumenControllerOperationParser implements OperationParserInterface */ public function __construct($controllerNamespace) { - if (strpos($controllerNamespace, '\\') === strlen($controllerNamespace) - 1) { - $controllerNamespace = mb_substr($controllerNamespace, 0, -1); + if (substr('$controllerNamespace', -1) !== '\\') { + $controllerNamespace .= '\\'; } $this->namespace = $controllerNamespace; diff --git a/tests/OperationParser/LumenControllerOperationParserTest.php b/tests/OperationParser/LumenControllerOperationParserTest.php index 9d4a54e..c0f4516 100644 --- a/tests/OperationParser/LumenControllerOperationParserTest.php +++ b/tests/OperationParser/LumenControllerOperationParserTest.php @@ -20,7 +20,7 @@ class LumenControllerOperationParserTest extends \PHPUnit_Framework_TestCase */ protected function setUp() { - $this->operationParser = new LumenControllerOperationParser('Iadvize\Test\\'); + $this->operationParser = new LumenControllerOperationParser('Iadvize\Test'); } /** From 5550dd7bb1fd54fa00e48449cf80d4177443ff1e Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Tue, 20 Oct 2015 16:52:54 +0200 Subject: [PATCH 07/10] misc: add MIT licence --- LICENCE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENCE.md diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 0000000..2c4e6a9 --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 iAdvize + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file From 2e6ac50e89e7955540d473e6a0b917f5ef045354 Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Wed, 21 Oct 2015 11:01:25 +0200 Subject: [PATCH 08/10] fix: delete cache --- cache.php | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 cache.php diff --git a/cache.php b/cache.php deleted file mode 100644 index 32eea0d..0000000 --- a/cache.php +++ /dev/null @@ -1,42 +0,0 @@ - - array ( - 'method' => 'POST', - 'uri' => '/button', - 'action' => - array ( - 'uses' => 'IadvizeTargetingApiServiceButtonController@create', - 'as' => 'createButton', - ), - ), - 1 => - array ( - 'method' => 'POST', - 'uri' => '/invitation', - 'action' => - array ( - 'uses' => 'IadvizeTargetingApiServiceInvitationController@create', - 'as' => 'createInvitation', - ), - ), - 2 => - array ( - 'method' => 'POST', - 'uri' => '/targetingRule', - 'action' => - array ( - 'uses' => 'IadvizeTargetingApiServiceTargetingRuleController@create', - 'as' => 'createTargetingRule', - ), - ), - 3 => - array ( - 'method' => 'POST', - 'uri' => '/visitorAttribute', - 'action' => - array ( - 'uses' => 'IadvizeTargetingApiServiceVisitorAttributeController@create', - 'as' => 'createVisitorAttribute', - ), - ), -); \ No newline at end of file From e0d8c7dc6b232b331580edbbccc2966adee66fba Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Wed, 21 Oct 2015 17:15:27 +0200 Subject: [PATCH 09/10] doc: better doc --- README.md | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index b388bdb..91ac161 100644 --- a/README.md +++ b/README.md @@ -23,48 +23,21 @@ require '/path/to/vendor/autoload.php'; $lumenOperationParser = new \Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser('Controllers\\Namespace\\'); -$dispatcher = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r, ['cacheFile' => 'route/file/path']) { +$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r, ['cacheFile' => 'route/file/path']) { \Iadvize\SwaggerizeFastRoute\addRoutes( - 'https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', + 'path/to/swagger/json', $r, $lumenOperationParser, - ['routeFile' => 'path/to/generated/route/file'] + ['routeFile' => 'path/to/generated/route/file', 'cacheEnabled' => false] ); }); -// Alternatively use cache -/** -$dispatcher = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r, ['cacheFile' => 'route/file/path']) { - \Iadvize\SwaggerizeFastRoute\addRoutes( - 'https://raw.githubusercontent.com/wordnik/swagger-spec/master/examples/v2.0/json/petstore.json', - $r, - $lumenOperationParser, - ['routeFile' => 'path/to/generated/route/file', 'cacheEnabled' => true] - ); -}); -*/ - // Fetch method and URI from somewhere -$httpMethod = $_SERVER['REQUEST_METHOD']; -$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); - -$routeInfo = $dispatcher->dispatch($httpMethod, $uri); -switch ($routeInfo[0]) { - case FastRoute\Dispatcher::NOT_FOUND: - // ... 404 Not Found - break; - case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: - $allowedMethods = $routeInfo[1]; - // ... 405 Method Not Allowed - break; - case FastRoute\Dispatcher::FOUND: - $handler = $routeInfo[1]; - $vars = $routeInfo[2]; - // ... call $handler with $vars - break; -} +// ... see FastRoute Dispatcher ``` +Alternatively to generate routes, you can simply cache first parse by setting `'cacheEnabled' => true` in addRoute function. + # Apply this to Lumen application 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. From 11d94430d0477b70fa3b2c7f436de1241a04f2da Mon Sep 17 00:00:00 2001 From: MarcFRICOU Date: Wed, 21 Oct 2015 17:16:11 +0200 Subject: [PATCH 10/10] style: :lipstick: --- src/Command/Scan.php | 3 ++- src/OperationParser/LumenControllerOperationParser.php | 6 +++--- src/functions.php | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Command/Scan.php b/src/Command/Scan.php index 6b75cf5..6b7c746 100644 --- a/src/Command/Scan.php +++ b/src/Command/Scan.php @@ -2,6 +2,7 @@ namespace Iadvize\SwaggerizeFastRoute\Command; +use Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -54,7 +55,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $routeStream = 'php://output'; } - $operationParser = new \Iadvize\SwaggerizeFastRoute\OperationParser\LumenControllerOperationParser($controllerNamespace); + $operationParser = new LumenControllerOperationParser($controllerNamespace); $routes = \Iadvize\SwaggerizeFastRoute\scan($swaggerFile, $operationParser); diff --git a/src/OperationParser/LumenControllerOperationParser.php b/src/OperationParser/LumenControllerOperationParser.php index 0790a9c..c76e213 100644 --- a/src/OperationParser/LumenControllerOperationParser.php +++ b/src/OperationParser/LumenControllerOperationParser.php @@ -56,9 +56,9 @@ public function getHandler(OperationReference $operation) $paths = explode('/', $path); // path start with a / unset($paths[0]); - foreach ($paths as &$path) { - $path[0] = strtoupper($path[0]); - } + $paths = array_map(function ($path) { + return ucfirst($path); + }, $paths); // path to 'relative' namespace $path = implode('\\', $paths); diff --git a/src/functions.php b/src/functions.php index 6cb6810..6d35c09 100644 --- a/src/functions.php +++ b/src/functions.php @@ -80,6 +80,10 @@ function addRoutes($swaggerJson, RouteCollector $routeCollector, OperationParser */ function cacheRoutes(array $routes, $stream) { + if (is_writable($stream)) { + throw new \LogicException($stream . ' is not writable'); + } + $routeResource = fopen($stream, 'w'); $serializedRoutes = var_export($routes, true);