diff --git a/src/Schema/Storage/AbstractTypeRegistry.php b/src/Schema/Storage/AbstractTypeRegistry.php index 6fe312a1..9c21d6a9 100644 --- a/src/Schema/Storage/AbstractTypeRegistry.php +++ b/src/Schema/Storage/AbstractTypeRegistry.php @@ -9,6 +9,10 @@ use GraphQL\Type\Definition\ListOfType; use Exception; use SilverStripe\Core\Injector\Injector; +use SilverStripe\GraphQL\Schema\SchemaBuilder; +use SilverStripe\GraphQL\Schema\Exception\EmptySchemaException; +use SilverStripe\Control\Controller; +use SilverStripe\GraphQL\Controller as GraphQLController; abstract class AbstractTypeRegistry { @@ -21,7 +25,30 @@ abstract class AbstractTypeRegistry */ public static function get(string $typename) { - return static::fromCache($typename); + try { + return static::fromCache($typename); + } catch (Exception $e) { + if (!Controller::has_curr() || + !(Controller::curr() instanceof GraphQLController) || + !Controller::curr()->autobuildEnabled() + ) { + throw $e; + } + // Try to rebuild the whole schema as fallback. + // This is to solve mysterious edge cases where schema files do not exist when they should. + // These edge cases are more likely on multi-server environments + $dirParts = explode(DIRECTORY_SEPARATOR, static::getSourceDirectory()); + $key = $dirParts[count($dirParts) - 1]; + $builder = SchemaBuilder::singleton(); + $schema = $builder->boot($key); + try { + $builder->build($schema, true); + } catch (EmptySchemaException $e) { + // noop + } + // Attempt to return again now the schema has been rebuilt. + return static::fromCache($typename); + } } abstract protected static function getSourceDirectory(): string; diff --git a/tests/Schema/IntegrationTest.php b/tests/Schema/IntegrationTest.php index f06f3be3..f42d1522 100644 --- a/tests/Schema/IntegrationTest.php +++ b/tests/Schema/IntegrationTest.php @@ -1215,6 +1215,12 @@ private function createSchema(TestSchemaBuilder $factory): Schema $factory->build($schema, true); + // Register as the default SchemaBuilder so that any calls to + // SchemaBuidler::singleton() get this TestSchemaBuilder + // This is important for the call in AbstractTypeRegisty::get() because + // otherwise a duplicate .graphql-generated folder will be created + Injector::inst()->registerService($factory, SchemaBuilder::class); + return $schema; }