diff --git a/Command/SwaggerDumpCommand.php b/Command/SwaggerDumpCommand.php index 6b9e93d..f5c0704 100644 --- a/Command/SwaggerDumpCommand.php +++ b/Command/SwaggerDumpCommand.php @@ -11,122 +11,153 @@ namespace Nelmio\ApiDocBundle\Command; +use Nelmio\ApiDocBundle\Formatter\SwaggerFormatter; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; - /** - * Symfony2 command to dump Swagger-compliant JSON files. + * Console command to dump Swagger-compliant API definitions. * * @author Bez Hermoso */ class SwaggerDumpCommand extends ContainerAwareCommand { + /** + * @var Filesystem + */ + protected $filesystem; + + /** + * @var SwaggerFormatter + */ + protected $formatter; + protected function configure() { + $this->filesystem = new Filesystem(); + $this - ->setDescription('Dump Swagger-compliant JSON files.') - ->addOption('resource', '', InputOption::VALUE_OPTIONAL, 'A specific resource API declaration to dump.') - ->addOption('all', '', InputOption::VALUE_NONE, 'Dump resource list and all API declarations.') - ->addOption('list-only', '', InputOption::VALUE_NONE, 'Dump resource list only.') - ->addArgument('destination', InputOption::VALUE_REQUIRED, 'Directory to dump JSON files in.', null) + ->setDescription('Dumps Swagger-compliant API definitions.') + ->addOption('resource', 'r', InputOption::VALUE_OPTIONAL, 'A specific resource API declaration to dump.') + ->addOption('list-only', 'l', InputOption::VALUE_NONE, 'Dump resource list only.') + ->addOption('pretty', 'p', InputOption::VALUE_NONE, 'Dump as prettified JSON.') + ->addArgument('destination', InputArgument::OPTIONAL, 'Directory to dump JSON files in.', null) ->setName('api:swagger:dump'); } protected function execute(InputInterface $input, OutputInterface $output) { $container = $this->getContainer(); - $destination = $input->getArgument('destination'); - $rootDir = $container->get('kernel')->getRootDir(); - $rootDir = $rootDir . '/..'; - - if (null === $destination) { - $destination = realpath($rootDir . '/' . $destination); - } - - $fs = new Filesystem(); - - if (!$fs->exists($destination)) { - $fs->mkdir($destination); - } - - $destination = realpath($destination); - - if ($input->getOption('all') && $input->getOption('resource')) { - throw new \RuntimeException('Cannot selectively dump a resource with the --all flag.'); - } + $extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor'); + $this->formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); if ($input->getOption('list-only') && $input->getOption('resource')) { throw new \RuntimeException('Cannot selectively dump a resource with the --list-only flag.'); } - if ($input->getOption('all') && $input->getOption('list-only')) { - throw new \RuntimeException('Cannot selectively dump resource list with the --all flag.'); - } - - $output->writeln(''); - $output->writeln('Reading annotations...'); - $extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor'); - $data = $extractor->all(); + $apiDocs = $extractor->all(); if ($input->getOption('list-only')) { - $this->dumpResourceList($destination, $data, $output); + $data = $this->getResourceList($apiDocs, $output); + $this->dump($data, null, $input, $output); + return; } if (false != ($resource = $input->getOption('resource'))) { - $this->dumpApiDeclaration($destination, $data, $resource, $output); + $data = $this->getApiDeclaration($apiDocs, $resource, $output); + if (count($data['apis']) === 0) { + throw new \InvalidArgumentException(sprintf('Resource "%s" does not exist.', $resource)); + } + $this->dump($data, $resource, $input, $output); + return; } - if ($input->getOption('all')) { - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - $this->dumpResourceList($destination, $data, $output); - $list = $formatter->format($data); - foreach ($list['apis'] as $api) { - $this->dumpApiDeclaration($destination, $data, substr($api['path'], 1), $output); + /* + * If --list-only and --resource is not specified, dump everything. + */ + $data = $this->getResourceList($apiDocs); + + if (!$input->getArguments('destination')) { + $output->writeln(''); + $output->writeln('Resource list: '); + } + + $this->dump($data, null, $input, $output, false); + + foreach ($data['apis'] as $api) { + + $resource = substr($api['path'], 1); + if (!$input->getArgument('destination')) { + $output->writeln(''); + $output->writeln(sprintf('API declaration for "%s" resource: ', $resource)); + } + $data = $this->getApiDeclaration($apiDocs, $resource, $output); + $this->dump($data, $resource, $input, $output, false); + } + } + + protected function dump(array $data, $resource, InputInterface $input, OutputInterface $output, $treatAsFile = true) + { + $destination = $input->getArgument('destination'); + + $content = json_encode($data, $input->getOption('pretty') ? JSON_PRETTY_PRINT : 0); + + if (!$destination) { + $output->writeln($content); + return; + } + + if ($treatAsFile === false) { + if (!$this->filesystem->exists($destination)) { + $this->filesystem->mkdir($destination); } } - } - protected function dumpResourceList($destination, array $data, OutputInterface $output) - { - $container = $this->getContainer(); - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); + if (!$resource) { - $list = $formatter->format($data); + if (!$treatAsFile) { + $destination = sprintf('%s/api-docs.json', rtrim($destination, '\\/')); + } + $message = sprintf('Dumping resource list to %s: ', $destination); + $this->writeToFile($content, $destination, $output, $message); - $fs = new Filesystem(); - $path = $destination . '/api-docs.json'; - - $string = sprintf('Dump resource list to %s: ', $path); - try { - $fs->dumpFile($path, json_encode($list)); - } catch (IOException $e) { - $output->writeln($string . ' NOT OK'); + return; } - $output->writeln($string . 'OK'); - } - protected function dumpApiDeclaration($destination, array $data, $resource, OutputInterface $output) - { - $container = $this->getContainer(); - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - - $list = $formatter->format($data, '/' . $resource); - - $fs = new Filesystem(); - $path = sprintf($destination . '/%s.json', $resource); - - $string = sprintf('Dump API declaration to %s: ', $path); - try { - $fs->dumpFile($path, json_encode($list)); - } catch (IOException $e) { - $output->writeln($string . ' NOT OK'); + if ($treatAsFile === false) { + $destination = sprintf('%s/%s.json', rtrim($destination, '\\/'), $resource); } - $output->writeln($string . 'OK'); + + $message = sprintf('Dump API declaration to %s: ', $destination); + $this->writeToFile($content, $destination, $output, $message); + } -} \ No newline at end of file + + protected function writeToFile($content, $file, OutputInterface $output, $message) + { + try { + $this->filesystem->dumpFile($file, $content); + $message .= ' OK'; + } catch (IOException $e) { + $message .= sprintf(' NOT OK - %s', $e->getMessage()); + } + + $output->writeln($message); + } + + protected function getResourceList(array $data) + { + return $this->formatter->format($data); + } + + protected function getApiDeclaration(array $data, $resource) + { + return $this->formatter->format($data, '/' . $resource); + } +} diff --git a/Resources/doc/swagger-support.md b/Resources/doc/swagger-support.md index 0e29934..702f4be 100644 --- a/Resources/doc/swagger-support.md +++ b/Resources/doc/swagger-support.md @@ -80,7 +80,7 @@ Et voila!, simply specify http://yourdomain.com/api-docs in your Swagger client The routes registered with the method above will read your `@ApiDoc` annotation during every request. Naturally, this will be slow because the bundle will parse your annotations every single time. For improved performance, you might be better off dumping the JSON output to the file-system and let your web-server serve them directly. If you want that, execute this command: ``` -php app/console api:swagger:dump --all app/Resources/swagger-docs +php app/console api:swagger:dump app/Resources/swagger-docs ``` The above command will dump JSON files under the `app/Resources/swagger-docs` directory (relative to your project root), and you can now process or server the files however you want. The destination defaults to the project root if not specified. @@ -89,12 +89,12 @@ The above command will dump JSON files under the `app/Resources/swagger-docs` di Dump the `api-docs.json` resource list file only: ``` -php app/console api:swagger:dump --list-only +php app/console api:swagger:dump --list-only api-docs.json ``` Dump a specific resource API declaration only: ``` -php app/console api:swagger:dump --resource=users +php app/console api:swagger:dump --resource=users users.json ``` The above command will dump the `/users` API declaration in an `users.json` file.