SOLID
Gato GraphQL suit l'approche SOLID pour l'architecture logicielle, en fournissant différentes entités pour traiter différentes responsabilités, afin de rendre le code maintenable, extensible et compréhensible.
Voici comment l'entité utilisateur est déjà fournie par le plugin. Le type User est fourni via ce code :
class UserTypeResolver extends AbstractTypeResolver
{
public function getTypeName(): string
{
return 'User';
}
public function getSchemaTypeDescription(): ?string
{
return $this->translationAPI->__('Representation of a user', "users");
}
public function getID(object $user)
{
return $this->usersAPI->getUserId($user);
}
public function getTypeDataLoaderClass(): string
{
return UserTypeDataLoader::class;
}
}Le type resolver ne charge pas directement les objets depuis la base de données, mais délègue cette tâche à un objet TypeDataLoader (dans l'exemple ci-dessus, de la classe UserTypeDataLoader).
L'ajout des champs username, email et url au type User se fait via un objet FieldResolver avec ce code :
class UserFieldResolver extends AbstractDBDataFieldResolver
{
public static function getClassesToAttachTo(): array
{
return [
UserTypeResolver::class,
];
}
public static function getFieldNamesToResolve(): array
{
return [
'username',
'email',
'url',
];
}
public function getSchemaFieldDescription(
TypeResolverInterface $typeResolver,
string $fieldName
): ?string {
$descriptions = [
'username' => $this->translationAPI->__("User's username handle", "users"),
'email' => $this->translationAPI->__("User's email", "users"),
'url' => $this->translationAPI->__("URL of the user's profile in the website", "users"),
];
return $descriptions[$fieldName];
}
public function getSchemaFieldType(
TypeResolverInterface $typeResolver,
string $fieldName
): ?string {
$types = [
'username' => SchemaDefinition::TYPE_STRING,
'email' => SchemaDefinition::TYPE_EMAIL,
'url' => SchemaDefinition::TYPE_URL,
];
return $types[$fieldName];
}
public function resolveValue(
TypeResolverInterface $typeResolver,
object $user,
string $fieldName,
array $fieldArgs = []
) {
switch ($fieldName) {
case 'username':
return $this->usersAPI->getUserLogin($user);
case 'email':
return $this->usersAPI->getUserEmail($user);
case 'url':
return $this->usersAPI->getUserURL($user);
}
return null;
}
}Comme on peut l'observer, la définition d'un champ pour le schéma GraphQL, et sa résolution, a été divisée en une multitude de fonctions :
getSchemaFieldDescriptiongetSchemaFieldTyperesolveValue
D'autres fonctions incluent :
getSchemaFieldArgs: pour déclarer les arguments du champ (incluant leur nom, description, type, et s'ils sont obligatoires ou non)isSchemaFieldResponseNonNullable: pour indiquer si un champ est non nullablegetImplementedInterfaceClasses: pour définir les resolvers pour les interfaces implémentées par les champsresolveFieldTypeResolverClass: pour définir le type resolver lorsque le champ est une connexionresolveFieldMutationResolverClass: pour définir le resolver lorsque le champ exécute des mutations
Ce code est plus lisible que si toutes les fonctionnalités étaient couvertes par une seule fonction, ou via un tableau de configuration, ce qui facilite l'implémentation et la maintenance des resolvers.