Architecture
ArchitectureSOLID

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 :

  • getSchemaFieldDescription
  • getSchemaFieldType
  • resolveValue

D'autres fonctions incluent :

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.