PHP code example of le0daniel / graphql-tools

1. Go to this page and download the library: Download le0daniel/graphql-tools library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

le0daniel / graphql-tools example snippets



    use GraphQlTools\Helper\Registry\SchemaRegistry;
    use GraphQlTools\Contract\TypeRegistry;
    use GraphQlTools\Definition\Field\Field;
    use GraphQlTools\Helper\QueryExecutor;
    use GraphQlTools\Definition\Extending\Extend;
    ypes
    $schemaRegistry->register(Type::class);
    
    // You can extend types and interfaces with additional fields
    // See: Extending Types
    $schemaRegistry->extend(
        Extend::type('Lion')->withFields(fn(TypeRegistry $registry) => [
            Field::withName('species')->ofType($registry->string())
        ])
    );

    $schema = $schemaRegistry->createSchema(
        RootQueryType::class, // Define
        'MutationRoot', // Your own root mutation type,
    );

    $executor = new QueryExecutor();

    $result = $executor->execute(
        $schema,
        ' query { whoami }',
        new Context(),
        [], // variables array
        null, // Root Value
        null, // operation name
    );

    use GraphQlTools\Helper\Registry\SchemaRegistry;
    use GraphQlTools\Utility\TypeMap;

    $schemaRegistry = new SchemaRegistry();
    
    [$types, $typeExtensions] = TypeMap::createTypeMapFromDirectory('/your/directory/with/GraphQL');
    
    $schemaRegistry->registerTypes($types);
    $schemaRegistry->extendMany($typeExtensions);

    use GraphQlTools\Helper\Registry\SchemaRegistry;
    use GraphQlTools\Utility\TypeMap;

    $schemaRegistry = new SchemaRegistry();
    $schemaRegistry->register(SomeName\Space\MyType::class);

    // You can now use both, the class name or the type name as in GraphQL.
    $registry->type(SomeName\Space\MyType::class) === $registry->type('My');

    use GraphQlTools\Helper\Registry\SchemaRegistry;
    use GraphQlTools\Helper\Registry\TagBasedSchemaRules;
    use GraphQlTools\Contract\SchemaRules;
    
    $schemaRegistry = new SchemaRegistry();
    // Register all kind of types
    $publicSchema = $schemaRegistry->createSchema(
        queryTypeName: 'Query',
        schemaRules: new TagBasedSchemaRules(ignoreWithTags: 'unstable', onlyWithTags: 'public')
    );
    
    $publicSchemaWithUnstableFields = $schemaRegistry->createSchema(
        queryTypeName: 'Query',
        schemaRules: new TagBasedSchemaRules(onlyWithTags: 'public')
    );

    class MyCustomRule implements SchemaRules {
        
        public function isVisible(Field|InputField|EnumValue $item): bool {
            // Determine if a field is visible or not.
            return Arr::contains('my-tag', $item->getTags());
        }
    }

use GraphQlTools\Definition\GraphQlType;
use GraphQlTools\Contract\TypeRegistry;
use GraphQlTools\Definition\Field\Field;
use GraphQL\Type\Definition\NonNull;

class QueryType extends GraphQlType {

    // Define Fields of the type. Use the type registry to reference all other types in the schema.
    // You MUST use the type registry for referencing all types. The type registry guarantees that the type is only 
    // created once and reused everywhere.
    protected function fields(TypeRegistry $registry) : array {
        return [
            Field::withName('currentUser')
                ->ofType(new NonNull($registry->string()))
                ->resolvedBy(fn(array $user) => $user['name']),
            // More fields
        ];
    }
    
    protected function description() : string{
        return 'Entry point into the schema query.';
    }
    
    // Optional
    protected function interfaces(): array {
        return [
            UserInterface::class,
            'Animal', 
        ];
    }
    
    // Optional, define middlewares for the resolver. See Middlewares.
    protected function middleware() : array|null{
        return [];
    }
}

use GraphQlTools\Definition\Field\Field;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\ListOfType;
/** @var \GraphQlTools\Contract\TypeRegistry $registry */

// In type Animal
Field::withName('myField')->ofType(new NonNull($registry->id()));
Field::withName('myOtherField')->ofType(new ListOfType($registry->type('Other')));

// Results in GraphQL
// type Animal {
//   myField: String!
//   myOtherField: [Other]
// }


    use GraphQlTools\Definition\GraphQlType;
    use GraphQlTools\Contract\TypeRegistry;
    use GraphQlTools\Definition\Field\Field;
    use GraphQL\Type\Definition\ResolveInfo;
    use GraphQL\Type\Definition\NonNull;
    
    
    final class AnimalType extends GraphQlType {
        // ...        
        protected function fields(TypeRegistry $registry) : array {
            
            return [
                // Uses the default resolver
                Field::withName('id')->ofType($registry->id()),
                
                // Define custom types using the repository
                Field::withName('customType')
                    ->withDescription('This is a custom type')
                    ->ofType($registry->type(CustomType::class))
                    ->tags('public', 'stable'),
                    
                // Using type name instead of class name
                Field::withName('customType2')
                    ->ofType($registry->type('Custom'))
                    ->tags('public', 'stable'),
                   
                // With Resolver
                Field::withName('userName')
                    ->ofType($registry->string())
                    ->resolvedBy(fn(User $user, array $arguments, $context, ResolveInfo $info): string => $user->name),
                
                // Define arguments 
                Field::withName('fieldWithArgs')
                    ->ofType($registry->string())
                    ->withArguments(
                        // Define named arguments, works for all fields
                        InputField::withName('name')
                            ->ofType(new NonNull($registry->string()))
                            ->withDefaultValue('Anonymous')
                            ->withDescription('My Description')
                    )
                    ->resolvedBy(function ($data, array $arguments, $context, ResolveInfo $resolveInfo): string {
                        return "Hello {$arguments['name']}";
                    })
                             
            ];
        }
    }

use GraphQlTools\Definition\Field\Field;
use GraphQlTools\Contract\TypeRegistry;
use GraphQlTools\Definition\GraphQlType;
use GraphQL\Type\Definition\NonNull;

class ReusableFields {
    public static function id(): Field {
        return Field::withName('id')
            ->ofTypeResolver(fn(TypeRegistry $registry) => new NonNull($registry->id()))
            ->withDescription('Globally unique identifier.')
            ->resolvedBy(fn(Identifiable $data): string => $data->globallyUniqueId());
    }
}

// Usage in type:
class MyType extends GraphQlType {
    protected function fields(TypeRegistry $registry) : array {
        return [
            ReusableFields::id()
                ->name('id')
                ->withDescription('Overwritten description...'),
            
            // Other Fields
            Field::withName('other')->ofType($registry->string()),
        ];
    }
}


$field->cost(2, fn(array $args): int => $args['first'] ?? 15);

use GraphQL\Type\Definition\ResolveInfo;
use Closure;

$middleware = function(mixed $data, array $arguments, $context, ResolveInfo $resolveInfo, Closure $next): mixed {
    // Do something before actually resolving the field.
    if (!$context->isAdmin()) {
        return null;
    }
    
    $result = $next($data, $arguments, $context, $resolveInfo);
    
    // Do something after the field was resolved. You can manipulate the result here.
    if ($result === 'super secret value') {
        return null;
    }
    
    return $result;
} 

use GraphQlTools\Definition\Field\Field;

Field::withName('fieldWithMiddleware')
    ->middleware(
        $middleware,
        function(mixed $data, array $arguments, $context, ResolveInfo $resolveInfo, Closure $next) {
            return $next($data, $arguments, $context, $resolveInfo);
        }
    )

use GraphQlTools\Helper\Registry\SchemaRegistry;
use GraphQlTools\Contract\TypeRegistry;
use GraphQlTools\Definition\Field\Field;
use GraphQlTools\Definition\Extending\Extend;
$schemaRegistry = new SchemaRegistry();

$schemaRegistry->extend(
    Extend::type('Animal')->withFields(fn(TypeRegistry $registry): array => [
            Field::withName('family')
                ->ofType($registry->string())
                ->resolvedBy(fn() => 'Animal Family')
        ]),
);

use GraphQlTools\Definition\Extending\ExtendGraphQlType;
use GraphQlTools\Contract\TypeRegistry;
use GraphQlTools\Helper\Registry\SchemaRegistry;

class ExtendsAnimalType extends ExtendGraphQlType {
    public function fields(TypeRegistry $registry) : array {
        return [
            Field::withName('family')
                ->ofType($registry->string())
                ->resolvedBy(fn() => 'Animal Family')
        ];
    }
    
    // Optional
    protected function middleware() : array{
        return [];
    }
    
    // Optional, can be inferred by class name
    // Follow naming pattern: Extends[TypeOrInterfaceName][Type|Interface]
    public function typeName(): string {
        return 'Animal';
    }
}

$schemaRegistry = new SchemaRegistry();

$schemaRegistry->extend(ExtendsAnimalType::class);
// If the class does not follow the naming patterns, you need to use the extended type name
$schemaRegistry->extend(ExtendsAnimalType::class, 'Animal');
// OR
$schemaRegistry->extend(new ExtendsAnimalType());

use GraphQlTools\Definition\Field\Field;
use GraphQlTools\Utility\Middleware\Federation;
use GraphQlTools\Contract\TypeRegistry;

/** @var TypeRegistry $registry */
Field::withName('extendedField')
    ->ofType($registry->string())
    ->middleware(Federation::key('id'))
    ->resolvedBy(fn(string $animalId) => "Only the ID is received, not the complete Animal Data.");

use GraphQlTools\Helper\QueryExecutor;
use GraphQlTools\Helper\Validation\QueryComplexityWithExtension;
use GraphQlTools\Helper\Validation\CollectDeprecatedFieldNotices;

$executor = new QueryExecutor(
    [fn($context) => new YourTelemetryExtension],
    [CollectDeprecatedFieldNotices::class, fn($context) => new QueryComplexityWithExtension($context->maxAllowedComplexity)],
    function(Throwable $throwable, \GraphQL\Error\Error $error): void {
        YourLogger::error($throwable);
    },
    function(Throwable $throwable): Throwable {
        match ($throwable::class) {
            AuthenticationError::class => GraphQlErrorWhichIsClientAware($throwable),
            default => $throwable
        }
    }
);

$result = $executor->execute(/* ... */);

// You can access extensions after the execution
$telemetryExtension = $result->getExtension(YourTelemetryExtension::class);
$application->storeTrace($telemetryExtension->getTrace());

// You can access validation rules after execution
$deprecationNotices = $result->getValidationRule(CollectDeprecatedFieldNotices::class);
$application->logDeprecatedUsages($deprecationNotices->getMessages());

$jsonResult = json_encode($result);

use GraphQlTools\Helper\QueryExecutor;
use GraphQlTools\Helper\Validation\ValidateDeferUsageOnFields;
use GraphQlTools\Helper\Extension\DeferExtension;
use GraphQlTools\Helper\Results\CompleteResult;
use GraphQlTools\Helper\Results\PartialResult;
use GraphQlTools\Helper\Results\PartialBatch;

$executor = new QueryExecutor(
    [fn() => new DeferExtension()],
    [new ValidateDeferUsageOnFields(10)]
);

$generator = $executor->executeGenerator(/* ... */);

/** @var CompleteResult|PartialResult $initialResult */
$initialResult = $generator->current();
/* SEND INITIAL RESPONSE */

$generator->next();
while ($result = $generator->current()) {
    $generator->next();
    
    /** @var PartialResult|PartialBatch $result */
    /* Send next chunk */
}

/* Close Response */

use GraphQlTools\Helper\Extension\Extension;
use GraphQlTools\Utility\Time;
use GraphQlTools\Data\ValueObjects\Events\FieldResolution;

class MyCustomExtension extends Extension {
    //...
    public function visitField(FieldResolution $event) : ?Closure{
        Log::debug('Will resolve field', ['name' => $event->info->fieldName, 'typeData' => $event->typeData, 'args' => $event->arguments]);
        return fn($resolvedValue) => Log::debug('did resolve field value to', [
            'value' => $resolvedValue, 
            'durationNs' => Time::durationNs($event->eventTimeInNanoSeconds),
        ]); 
    }
}