Skip to content

Commit 541b738

Browse files
fix(graphql): add clearer error message when TwigBundle is disabled but graphQL clients are enabled (#5064)
1 parent defe717 commit 541b738

File tree

5 files changed

+59
-7
lines changed

5 files changed

+59
-7
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 3.0.3
4+
5+
* Graphql: add a clearer error message when TwigBundle is disabled but graphQL clients are enabled (#5064)
6+
37
## 3.0.2
48

59
* Metadata: generate skolem IRI by default, use `genId: false` to disable **BC**

src/GraphQl/Action/EntrypointAction.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class EntrypointAction
3434
{
3535
private int $debug;
3636

37-
public function __construct(private readonly SchemaBuilderInterface $schemaBuilder, private readonly ExecutorInterface $executor, private readonly GraphiQlAction $graphiQlAction, private readonly GraphQlPlaygroundAction $graphQlPlaygroundAction, private readonly NormalizerInterface $normalizer, private readonly ErrorHandlerInterface $errorHandler, bool $debug = false, private readonly bool $graphiqlEnabled = false, private readonly bool $graphQlPlaygroundEnabled = false, private readonly ?string $defaultIde = null)
37+
public function __construct(private readonly SchemaBuilderInterface $schemaBuilder, private readonly ExecutorInterface $executor, private readonly ?GraphiQlAction $graphiQlAction, private readonly ?GraphQlPlaygroundAction $graphQlPlaygroundAction, private readonly NormalizerInterface $normalizer, private readonly ErrorHandlerInterface $errorHandler, bool $debug = false, private readonly bool $graphiqlEnabled = false, private readonly bool $graphQlPlaygroundEnabled = false, private readonly ?string $defaultIde = null)
3838
{
3939
$this->debug = $debug ? DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE : DebugFlag::NONE;
4040
}
@@ -43,11 +43,11 @@ public function __invoke(Request $request): Response
4343
{
4444
try {
4545
if ($request->isMethod('GET') && 'html' === $request->getRequestFormat()) {
46-
if ('graphiql' === $this->defaultIde && $this->graphiqlEnabled) {
46+
if ('graphiql' === $this->defaultIde && $this->graphiqlEnabled && $this->graphiQlAction) {
4747
return ($this->graphiQlAction)($request);
4848
}
4949

50-
if ('graphql-playground' === $this->defaultIde && $this->graphQlPlaygroundEnabled) {
50+
if ('graphql-playground' === $this->defaultIde && $this->graphQlPlaygroundEnabled && $this->graphQlPlaygroundAction) {
5151
return ($this->graphQlPlaygroundAction)($request);
5252
}
5353
}

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

+15-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
use Symfony\Component\Uid\AbstractUid;
5454
use Symfony\Component\Validator\Validator\ValidatorInterface;
5555
use Symfony\Component\Yaml\Yaml;
56+
use Twig\Environment;
5657

5758
/**
5859
* The extension of this bundle.
@@ -462,9 +463,12 @@ private function registerGraphQlConfiguration(ContainerBuilder $container, array
462463
{
463464
$enabled = $this->isConfigEnabled($container, $config['graphql']);
464465

466+
$graphiqlEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']);
467+
$graphqlPlayGroundEnabled = $enabled && $this->isConfigEnabled($container, $config['graphql']['graphql_playground']);
468+
465469
$container->setParameter('api_platform.graphql.enabled', $enabled);
466-
$container->setParameter('api_platform.graphql.graphiql.enabled', $enabled && $this->isConfigEnabled($container, $config['graphql']['graphiql']));
467-
$container->setParameter('api_platform.graphql.graphql_playground.enabled', $enabled && $this->isConfigEnabled($container, $config['graphql']['graphql_playground']));
470+
$container->setParameter('api_platform.graphql.graphiql.enabled', $graphiqlEnabled);
471+
$container->setParameter('api_platform.graphql.graphql_playground.enabled', $graphqlPlayGroundEnabled);
468472
$container->setParameter('api_platform.graphql.collection.pagination', $config['graphql']['collection']['pagination']);
469473

470474
if (!$enabled) {
@@ -476,6 +480,15 @@ private function registerGraphQlConfiguration(ContainerBuilder $container, array
476480

477481
$loader->load('graphql.xml');
478482

483+
// @phpstan-ignore-next-line because PHPStan uses the container of the test env cache and in test the parameter kernel.bundles always contains the key TwigBundle
484+
if (!class_exists(Environment::class) || !isset($container->getParameter('kernel.bundles')['TwigBundle'])) {
485+
if ($graphiqlEnabled || $graphqlPlayGroundEnabled) {
486+
throw new RuntimeException(sprintf('GraphiQL and GraphQL Playground interfaces depend on Twig. Please activate TwigBundle for the %s environnement or disable GraphiQL and GraphQL Playground.', $container->getParameter('kernel.environment')));
487+
}
488+
$container->removeDefinition('api_platform.graphql.action.graphiql');
489+
$container->removeDefinition('api_platform.graphql.action.graphql_playground');
490+
}
491+
479492
$container->registerForAutoconfiguration(QueryItemResolverInterface::class)
480493
->addTag('api_platform.graphql.query_resolver');
481494
$container->registerForAutoconfiguration(QueryCollectionResolverInterface::class)

src/Symfony/Bundle/Resources/config/graphql.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949
<service id="api_platform.graphql.action.entrypoint" class="ApiPlatform\GraphQl\Action\EntrypointAction" public="true">
5050
<argument type="service" id="api_platform.graphql.schema_builder" />
5151
<argument type="service" id="api_platform.graphql.executor" />
52-
<argument type="service" id="api_platform.graphql.action.graphiql" />
53-
<argument type="service" id="api_platform.graphql.action.graphql_playground" />
52+
<argument type="service" id="api_platform.graphql.action.graphiql" on-invalid="null"/>
53+
<argument type="service" id="api_platform.graphql.action.graphql_playground" on-invalid="null"/>
5454
<argument type="service" id="serializer" />
5555
<argument type="service" id="api_platform.graphql.error_handler" />
5656
<argument>%kernel.debug%</argument>

tests/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

+35
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@
7070
use Prophecy\PhpUnit\ProphecyTrait;
7171
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
7272
use Symfony\Bundle\SecurityBundle\SecurityBundle;
73+
use Symfony\Bundle\TwigBundle\TwigBundle;
7374
use Symfony\Component\DependencyInjection\ContainerBuilder;
75+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
7476
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
7577
use Symfony\Component\HttpFoundation\Response;
7678
use Symfony\Component\Uid\AbstractUid;
@@ -163,6 +165,7 @@ protected function setUp(): void
163165
'kernel.bundles' => [
164166
'DoctrineBundle' => DoctrineBundle::class,
165167
'SecurityBundle' => SecurityBundle::class,
168+
'TwigBundle' => TwigBundle::class,
166169
],
167170
'kernel.bundles_metadata' => [
168171
'TestBundle' => [
@@ -173,6 +176,7 @@ protected function setUp(): void
173176
],
174177
'kernel.project_dir' => __DIR__.'/../../../Fixtures/app',
175178
'kernel.debug' => false,
179+
'kernel.environment' => 'test',
176180
]);
177181

178182
$this->container = new ContainerBuilder($containerParameterBag);
@@ -693,6 +697,37 @@ public function testGraphQlConfiguration(): void
693697
$this->assertServiceHasTags('api_platform.graphql.normalizer.runtime_exception', ['serializer.normalizer']);
694698
}
695699

700+
public function testRuntimeExceptionIsThrownIfTwigIsNotEnabledButGraphqlClientsAre(): void
701+
{
702+
$config = self::DEFAULT_CONFIG;
703+
$config['api_platform']['graphql']['enabled'] = true;
704+
$this->container->getParameterBag()->set('kernel.bundles', [
705+
'DoctrineBundle' => DoctrineBundle::class,
706+
'SecurityBundle' => SecurityBundle::class,
707+
]);
708+
$this->expectException(RuntimeException::class);
709+
$this->expectExceptionMessage('GraphiQL and GraphQL Playground interfaces depend on Twig. Please activate TwigBundle for the test environnement or disable GraphiQL and GraphQL Playground.');
710+
711+
(new ApiPlatformExtension())->load($config, $this->container);
712+
}
713+
714+
public function testGraphqlClientsDefinitionsAreRemovedIfDisabled(): void
715+
{
716+
$config = self::DEFAULT_CONFIG;
717+
$config['api_platform']['graphql']['enabled'] = true;
718+
$config['api_platform']['graphql']['graphiql']['enabled'] = false;
719+
$config['api_platform']['graphql']['graphql_playground']['enabled'] = false;
720+
$this->container->getParameterBag()->set('kernel.bundles', [
721+
'DoctrineBundle' => DoctrineBundle::class,
722+
'SecurityBundle' => SecurityBundle::class,
723+
]);
724+
725+
(new ApiPlatformExtension())->load($config, $this->container);
726+
727+
$this->assertNotContainerHasService('api_platform.graphql.action.graphiql');
728+
$this->assertNotContainerHasService('api_platform.graphql.action.graphql_playground');
729+
}
730+
696731
public function testDoctrineOrmConfiguration(): void
697732
{
698733
$config = self::DEFAULT_CONFIG;

0 commit comments

Comments
 (0)