diff --git a/Command/GraphQLDumpSchemaCommand.php b/Command/GraphQLDumpSchemaCommand.php index 0d4408287..353815f8a 100644 --- a/Command/GraphQLDumpSchemaCommand.php +++ b/Command/GraphQLDumpSchemaCommand.php @@ -12,6 +12,8 @@ namespace Overblog\GraphQLBundle\Command; use GraphQL\Type\Introspection; +use GraphQL\Utils\SchemaPrinter; +use Overblog\GraphQLBundle\Request\Executor; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -37,6 +39,13 @@ protected function configure() null, InputOption::VALUE_OPTIONAL, 'The schema name to generate.' + ) + ->addOption( + 'format', + null, + InputOption::VALUE_OPTIONAL, + 'The schema name to generate ("graphqls" or "json"). ', + 'json' ); } @@ -44,25 +53,43 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output = new SymfonyStyle($input, $output); - $request = [ - 'query' => Introspection::getIntrospectionQuery(false), - 'variables' => [], - 'operationName' => null, - ]; + $format = strtolower($input->getOption('format')); $schemaName = $input->getOption('schema'); - $container = $this->getContainer(); - $result = $container - ->get('overblog_graphql.request_executor') - ->execute($request, [], $schemaName) - ->toArray(); + $requestExecutor = $container->get('overblog_graphql.request_executor'); + $file = $input->getOption('file') ?: $container->getParameter('kernel.root_dir').sprintf('/../var/schema%s.%s', $schemaName ? '.'.$schemaName : '', $format); - $file = $input->getOption('file') ?: $container->getParameter('kernel.root_dir').sprintf('/../var/schema%s.json', $schemaName ? '.'.$schemaName : ''); + $content = $this->createFileContent($requestExecutor, $format, $schemaName); + file_put_contents($file, $content); - $schema = json_encode($result['data']); + $output->success(sprintf('GraphQL schema "%s" was successfully dumped.', realpath($file))); + } - file_put_contents($file, $schema); + private function createFileContent(Executor $requestExecutor, $format, $schemaName) + { + switch ($format) { + case 'json': + $request = [ + 'query' => Introspection::getIntrospectionQuery(false), + 'variables' => [], + 'operationName' => null, + ]; - $output->success(sprintf('GraphQL schema "%s" was successfully dumped.', realpath($file))); + $result = $requestExecutor + ->execute($request, [], $schemaName) + ->toArray(); + + $content = json_encode($result['data']); + break; + + case 'graphqls': + $content = SchemaPrinter::doPrint($requestExecutor->getSchema($schemaName)); + break; + + default: + throw new \InvalidArgumentException(sprintf('Unknown format %s.', json_encode($format))); + } + + return $content; } } diff --git a/Tests/Functional/Command/GraphDumpSchemaCommandTest.php b/Tests/Functional/Command/GraphDumpSchemaCommandTest.php index c55e5e3c9..3df6ff154 100644 --- a/Tests/Functional/Command/GraphDumpSchemaCommandTest.php +++ b/Tests/Functional/Command/GraphDumpSchemaCommandTest.php @@ -14,30 +14,80 @@ use Overblog\GraphQLBundle\Command\GraphQLDumpSchemaCommand; use Overblog\GraphQLBundle\Tests\Functional\TestCase; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Tester\CommandTester; class GraphDumpSchemaCommandTest extends TestCase { - public function testExecute() + /** + * @var Command + */ + private $command; + + /** + * @var CommandTester + */ + private $commandTester; + + /** + * @var string + */ + private $cacheDir; + + public function setUp() { + parent::setUp(); $client = static::createClient(['test_case' => 'connection']); $kernel = $client->getKernel(); $application = new Application($kernel); $application->add(new GraphQLDumpSchemaCommand()); + $this->command = $application->find('graph:dump-schema'); + $this->commandTester = new CommandTester($this->command); + $this->cacheDir = $kernel->getCacheDir(); + } + + /** + * @param $format + * @param bool $withFormatOption + * @dataProvider formatDataProvider + */ + public function testDump($format, $withFormatOption = true) + { + $file = $this->cacheDir.'/schema.'.$format; - $command = $application->find('graph:dump-schema'); - $file = $kernel->getCacheDir().'/schema.json'; + $input = [ + 'command' => $this->command->getName(), + '--file' => $file, + ]; - $commandTester = new CommandTester($command); - $commandTester->execute( - [ - 'command' => $command->getName(), - '--file' => $file, - ] - ); + if ($withFormatOption) { + $input['--format'] = $format; + } + $this->commandTester->execute($input); - $this->assertEquals(0, $commandTester->getStatusCode()); - $this->assertEquals(trim(file_get_contents(__DIR__.'/schema.json')), file_get_contents($file)); + $this->assertEquals(0, $this->commandTester->getStatusCode()); + $this->assertEquals(trim(file_get_contents(__DIR__.'/schema.'.$format)), trim(file_get_contents($file))); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Unknown format "fake". + */ + public function testInvalidFormat() + { + $this->commandTester->execute([ + 'command' => $this->command->getName(), + '--format' => 'fake', + ]); + } + + public function formatDataProvider() + { + return [ + ['json', false], + ['json', true], + ['graphqls'], + ]; } } diff --git a/Tests/Functional/Command/schema.graphqls b/Tests/Functional/Command/schema.graphqls new file mode 100644 index 000000000..644a17fd4 --- /dev/null +++ b/Tests/Functional/Command/schema.graphqls @@ -0,0 +1,66 @@ +# Information about pagination in a connection. +type PageInfo { + # When paginating forwards, are there more items? + hasNextPage: Boolean! + + # When paginating backwards, are there more items? + hasPreviousPage: Boolean! + + # When paginating backwards, the cursor to continue. + startCursor: String + + # When paginating forwards, the cursor to continue. + endCursor: String +} + +type Query { + user: User +} + +type User { + # the user name + name: String + friends(after: String = null, first: Int = null, before: String = null, last: Int = null): friendConnection + friendsForward(after: String = null, first: Int = null): userConnection + friendsBackward(before: String = null, last: Int = null): userConnection +} + +# A connection to a list of items. +type friendConnection { + totalCount: Int + + # Information to aid in pagination. + pageInfo: PageInfo! + + # Information to aid in pagination. + edges: [friendEdge] +} + +# An edge in a connection. +type friendEdge { + friendshipTime: String + + # The item at the end of the edge. + node: User + + # A cursor for use in pagination. + cursor: String! +} + +# A connection to a list of items. +type userConnection { + # Information to aid in pagination. + pageInfo: PageInfo! + + # Information to aid in pagination. + edges: [userEdge] +} + +# An edge in a connection. +type userEdge { + # The item at the end of the edge. + node: User + + # A cursor for use in pagination. + cursor: String! +} diff --git a/composer.json b/composer.json index eba810a4d..f09db0424 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "symfony/framework-bundle": "^2.7|^3.1", "symfony/options-resolver": "^2.7|^3.1", "symfony/property-access": "^2.7|^3.1", - "webonyx/graphql-php": "^0.9.0" + "webonyx/graphql-php": "^0.9.4" }, "suggest": { "twig/twig": "If you want to use graphiQL.",