diff --git a/src/Plugin/GraphQLCompose/GraphQLComposeEntityTypeBase.php b/src/Plugin/GraphQLCompose/GraphQLComposeEntityTypeBase.php index 057afc7963341be98d65bc98d608a4c3ebca9ee7..fc9d0b7373912786e16f36372528aa5c97d540d5 100644 --- a/src/Plugin/GraphQLCompose/GraphQLComposeEntityTypeBase.php +++ b/src/Plugin/GraphQLCompose/GraphQLComposeEntityTypeBase.php @@ -253,18 +253,26 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ * Register unions and interfaces only if there is multiple enabled bundles. */ public function registerTypes(): void { - $bundles = $this->getBundles(); if (!$bundles) { return; } - // Register a bundle types into the schema. + $this->registerEntityInterface(); + $this->registerEntityUnion(); + $this->registerEntityQuery(); + foreach ($bundles as $bundle) { $this->registerBundleTypes($bundle); + $this->registerBundleQueries($bundle); + $this->registerBundleFieldUnions($bundle); } + } - // Create generic entity wide interface. + /** + * Register a generic entity wide interface. + */ + protected function registerEntityInterface(): void { $interface_fields = $this->gqlFieldTypeManager->getInterfaceFields($this->getEntityTypeId()); if ($interface_fields) { $interface = new InterfaceType([ @@ -289,11 +297,15 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ $this->gqlSchemaTypeManager->add($interface); } + } - // Create generic entity wide union. + /** + * Register a generic entity wide union. + */ + protected function registerEntityUnion(): void { $union_types = array_map( fn(EntityTypeWrapper $bundle): string => $bundle->getTypeSdl(), - $bundles + $this->getBundles() ); $entity_union = new UnionType([ @@ -306,10 +318,14 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ ]); $this->gqlSchemaTypeManager->add($entity_union); + } - // Create generic entity wide query. + /** + * Register a generic entity wide query. + */ + protected function registerEntityQuery(): void { $enabled_query_bundles = array_filter( - $bundles, + $this->getBundles(), fn(EntityTypeWrapper $bundle) => $bundle->isQueryLoadEnabled() ); @@ -390,8 +406,15 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ ]); $this->gqlSchemaTypeManager->add($entityType); + } - // Create bundle query. + /** + * Register individual bundle queries into the schema. + * + * @param \Drupal\graphql_compose\Wrapper\EntityTypeWrapper $bundle + * The bundle to register. + */ + protected function registerBundleQueries(EntityTypeWrapper $bundle): void { if (!$this->isQueryLoadSimple() && $bundle->isQueryLoadEnabled()) { $entityQuery = new ObjectType([ 'name' => 'Query', @@ -412,7 +435,7 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ 'type' => Type::string(), 'description' => (string) $this->t('Optionally set the response language. Eg en, ja, fr.'), ] : [], - 'revision' => $bundle->getEntityType()->isRevisionable() ? [ + 'revision' => $this->getEntityType()->isRevisionable() ? [ 'type' => Type::id(), 'description' => (string) $this->t('Optionally set the revision of the entity. Eg current, latest, or an ID.'), ] : [], @@ -423,6 +446,19 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ $this->gqlSchemaTypeManager->extend($entityQuery); } + } + + /** + * Register a bundle field union types into the schema. + * + * @param \Drupal\graphql_compose\Wrapper\EntityTypeWrapper $bundle + * The bundle to register. + */ + protected function registerBundleFieldUnions(EntityTypeWrapper $bundle): void { + $fields = $this->gqlFieldTypeManager->getBundleFields( + $this->getEntityTypeId(), + $bundle->getEntity()->id() + ); // Add per-field union types. foreach ($fields as $field_plugin) { @@ -464,23 +500,33 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ * Resolve unions only if there is multiple enabled bundles. */ public function registerResolvers(ResolverRegistryInterface $registry, ResolverBuilder $builder): void { - $bundles = $this->getBundles(); if (!$bundles) { return; } - $entity_class = $this->entityTypeManager - ->getDefinition($this->getEntityTypeId()) - ->getClass(); + $this->resolveEntityQuery($registry, $builder); + $this->resolveEntityUnion($registry, $builder); foreach ($bundles as $bundle) { - $this->registerBundleResolvers($registry, $builder, $bundle, $entity_class); + $this->resolveBundleTypes($registry, $builder, $bundle); + $this->resolveBundleQueries($registry, $builder, $bundle); + $this->resolveBundleFieldUnions($registry, $builder, $bundle); } + } + /** + * Resolve generic entity query. + * + * @param \Drupal\graphql\GraphQL\ResolverRegistryInterface $registry + * The resolver registry. + * @param \Drupal\graphql\GraphQL\ResolverBuilder $builder + * The resolver builder. + */ + protected function resolveEntityQuery(ResolverRegistryInterface $registry, ResolverBuilder $builder): void { // Resolve generic load by id query. $enabled_query_bundles = array_filter( - $bundles, + $this->getBundles(), fn(EntityTypeWrapper $bundle) => $bundle->isQueryLoadEnabled() ); @@ -507,24 +553,38 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ ) ); } + } + + /** + * Resolve generic entity wide union. + * + * @param \Drupal\graphql\GraphQL\ResolverRegistryInterface $registry + * The resolver registry. + * @param \Drupal\graphql\GraphQL\ResolverBuilder $builder + * The resolver builder. + */ + protected function resolveEntityUnion(ResolverRegistryInterface $registry, ResolverBuilder $builder): void { + // The expected class for the entity type. + $class = $this->entityTypeManager + ->getDefinition($this->getEntityTypeId()) + ->getClass(); // Resolve generic entity wide union. $registry->addTypeResolver( $this->getUnionTypeSdl(), - function ($value) use ($entity_class) { - if (!is_a($value, $entity_class, TRUE)) { - throw new UserError(sprintf('Could not resolve union entity type %s', $entity_class)); + function ($value) use ($class) { + if (!is_a($value, $class, TRUE)) { + throw new UserError(sprintf('Could not resolve union entity type %s', $class)); } $bundle = $this->getBundle($value->bundle()); if (!$bundle) { - throw new UserError(sprintf('Could not resolve union entity bundle %s::%s, is it enabled?', $entity_class, $value->bundle())); + throw new UserError(sprintf('Could not resolve union entity bundle %s::%s, is it enabled?', $class, $value->bundle())); } return $bundle->getTypeSdl(); } ); - } /** @@ -535,28 +595,31 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ * @param \Drupal\graphql\GraphQL\ResolverBuilder $builder * The resolver builder. * @param \Drupal\graphql_compose\Wrapper\EntityTypeWrapper $bundle - * The bundle to register. - * @param string $entity_class - * The bundle's base entity class. + * The bundle to resolve. */ - protected function registerBundleResolvers(ResolverRegistryInterface $registry, ResolverBuilder $builder, EntityTypeWrapper $bundle, string $entity_class): void { - // Add bundle type resolution. + protected function resolveBundleTypes(ResolverRegistryInterface $registry, ResolverBuilder $builder, EntityTypeWrapper $bundle): void { + + // The expected class for the entity type. + $class = $this->entityTypeManager + ->getDefinition($this->getEntityTypeId()) + ->getClass(); + $registry->addTypeResolver( $bundle->getTypeSdl(), - function ($value) use ($entity_class) { - if (!is_a($value, $entity_class, TRUE)) { - throw new UserError(sprintf('Could not resolve entity type %s', $entity_class)); + function ($value) use ($class) { + if (!is_a($value, $class, TRUE)) { + throw new UserError(sprintf('Could not resolve entity type %s', $class)); } return $this->getBundle($value->bundle())->getTypeSdl(); } ); + // Add fields to bundle type. $fields = $this->gqlFieldTypeManager->getBundleFields( $this->getEntityTypeId(), $bundle->getEntity()->id() ); - // Add fields to bundle type. foreach ($fields as $field_plugin) { $registry->addFieldResolver( $bundle->getTypeSdl(), @@ -567,8 +630,19 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ ->map('value', $field_plugin->getProducers($builder)), ); } + } - // Enable loading by query with id. + /** + * Resolve bundle queries for the schema. + * + * @param \Drupal\graphql\GraphQL\ResolverRegistryInterface $registry + * The resolver registry. + * @param \Drupal\graphql\GraphQL\ResolverBuilder $builder + * The resolver builder. + * @param \Drupal\graphql_compose\Wrapper\EntityTypeWrapper $bundle + * The bundle to resolve. + */ + protected function resolveBundleQueries(ResolverRegistryInterface $registry, ResolverBuilder $builder, EntityTypeWrapper $bundle): void { if (!$this->isQueryLoadSimple() && $bundle->isQueryLoadEnabled()) { $registry->addFieldResolver( 'Query', @@ -586,6 +660,25 @@ abstract class GraphQLComposeEntityTypeBase extends PluginBase implements GraphQ ) ); } + } + + /** + * Resolve bundle field unions for the schema. + * + * @param \Drupal\graphql\GraphQL\ResolverRegistryInterface $registry + * The resolver registry. + * @param \Drupal\graphql\GraphQL\ResolverBuilder $builder + * The resolver builder. + * @param \Drupal\graphql_compose\Wrapper\EntityTypeWrapper $bundle + * The bundle to register. + */ + protected function resolveBundleFieldUnions(ResolverRegistryInterface $registry, ResolverBuilder $builder, EntityTypeWrapper $bundle): void { + + // Get the bundle fields. + $fields = $this->gqlFieldTypeManager->getBundleFields( + $this->getEntityTypeId(), + $bundle->getEntity()->id() + ); // Add union field resolution for non-simple unions. foreach ($fields as $field_plugin) {