Architektur
ArchitekturSOLID

SOLID

Gato GraphQL folgt dem SOLID-Ansatz für die Softwarearchitektur und stellt verschiedene Entitäten bereit, die unterschiedliche Verantwortlichkeiten übernehmen, um den Code wartbar, erweiterbar und verständlich zu machen.

So wird die Benutzerentität bereits vom Plugin bereitgestellt. Der Typ User wird über diesen Code zur Verfügung gestellt:

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;
  }
}

Der Type Resolver lädt die Objekte nicht direkt aus der Datenbank, sondern delegiert diese Aufgabe an ein TypeDataLoader-Objekt (im obigen Beispiel an die Klasse UserTypeDataLoader).

Das Hinzufügen der Felder username, email und url zum Typ User erfolgt über ein FieldResolver-Objekt mit diesem 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;
  }
}

Wie zu erkennen ist, wurde die Definition eines Feldes für das GraphQL-Schema sowie dessen Auflösung auf eine Vielzahl von Funktionen aufgeteilt:

  • getSchemaFieldDescription
  • getSchemaFieldType
  • resolveValue

Weitere Funktionen umfassen:

Dieser Code ist lesbarer als wenn die gesamte Funktionalität über eine einzelne Funktion oder ein Konfigurations-Array abgewickelt wird, was die Implementierung und Pflege der Resolver erheblich vereinfacht.