PHP code example of monkeyscloud / monkeyslegion-graphql

1. Go to this page and download the library: Download monkeyscloud/monkeyslegion-graphql 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/ */

    

monkeyscloud / monkeyslegion-graphql example snippets


use MonkeysLegion\GraphQL\Attribute\{Type, Field};

#[Type(description: 'A user')]
final class UserType
{
    #[Field]
    public function id(User $root): int
    {
        return $root->id;
    }

    #[Field]
    public function name(User $root): string
    {
        return $root->name;
    }

    #[Field(description: 'Email address')]
    public function email(User $root): string
    {
        return $root->email;
    }
}

use MonkeysLegion\GraphQL\Attribute\{Query, Arg};
use MonkeysLegion\GraphQL\Context\GraphQLContext;

#[Query(name: 'user', description: 'Get user by ID')]
final class GetUserQuery
{
    public function __construct(private UserRepository $users) {}

    public function __invoke(
        mixed $root,
        #[Arg(description: 'User ID')] int $id,
        GraphQLContext $context,
    ): ?User {
        return $this->users->find($id);
    }
}

use MonkeysLegion\GraphQL\Attribute\{Mutation, Arg};

#[Mutation(name: 'createUser', description: 'Create a new user')]
final class CreateUserMutation
{
    public function __construct(private UserRepository $users) {}

    public function __invoke(
        mixed $root,
        #[Arg] string $name,
        #[Arg] string $email,
    ): User {
        return $this->users->create($name, $email);
    }
}

use MonkeysLegion\GraphQL\Loader\DataLoader;

final class UserLoader extends DataLoader
{
    public function __construct(private UserRepository $users) {}

    protected function batchLoad(array $keys): array
    {
        $users = $this->users->findByIds($keys);
        return array_map(
            fn(int $id) => $users[$id] ?? null,
            $keys,
        );
    }
}

use MonkeysLegion\GraphQL\Type\ConnectionType;

// Automatically creates UserConnection, UserEdge, PageInfo types
$connectionType = ConnectionType::create('User', $userType);

use MonkeysLegion\GraphQL\Attribute\Subscription;

#[Subscription(name: 'messageAdded', description: 'New message')]
final class MessageAddedSubscription
{
    public function __invoke(mixed $root): Message
    {
        return $root;
    }
}

#[Mutation(name: 'uploadFile')]
final class UploadFileMutation
{
    public function __invoke(
        mixed $root,
        #[Arg] UploadedFileInterface $file,
    ): string {
        $file->moveTo('/uploads/' . $file->getClientFilename());
        return $file->getClientFilename();
    }
}

use MonkeysLegion\Entity\Attribute\Entity;
use MonkeysLegion\Entity\Attribute\Id;
use MonkeysLegion\Entity\Attribute\Column;

#[Entity(table: 'products')]
class Product
{
    #[Id]
    public int $id;

    #[Column(type: 'varchar', length: 255)]
    public string $name;

    #[Column(type: 'text')]
    public string $description;

    #[Column(type: 'decimal')]
    public float $price;

    #[Column(type: 'boolean')]
    public bool $active;

    #[Column(type: 'datetime')]
    public \DateTimeImmutable $createdAt;
}

use MonkeysLegion\GraphQL\Scanner\EntityTypeMapper;

$mapper = new EntityTypeMapper();

// Maps all typed properties → GraphQL fields automatically:
//   int    → Int!        float  → Float!
//   string → String!     bool   → Boolean!
//   DateTime* → DateTime!  (custom scalar)
//   ?string → String     (nullable)
$typeConfig = $mapper->map(Product::class);
// Returns: ['name' => 'Product', 'fields' => ['id' => ..., 'name' => ..., ...]]

// Map multiple entities at once
$types = $mapper->mapAll([Product::class, Category::class, Order::class]);

use MonkeysLegion\GraphQL\Resolver\EntityResolver;
use MonkeysLegion\GraphQL\Type\ConnectionType;

// Single entity by ID
//   query { product(id: 42) { name price } }
$findProduct = EntityResolver::findById(
    Product::class,
    ProductRepository::class, // optional — defaults to Product::class . 'Repository'
);

// List all entities
//   query { products { name price active } }
$listProducts = EntityResolver::findAll(Product::class);

// Relay-style pagination with cursors
//   query { products(first: 10, after: "Y3Vyc29yOjk=") {
//     edges { node { name } cursor }
//     pageInfo { hasNextPage endCursor }
//     totalCount
//   }}
$paginatedProducts = EntityResolver::connection(Product::class);

use MonkeysLegion\GraphQL\Attribute\{Type, Field, Query, Arg};
use MonkeysLegion\GraphQL\Context\GraphQLContext;

// 1. Define the GraphQL type wrapping the entity
#[Type(description: 'A product in the catalog')]
final class ProductType
{
    #[Field]
    public function id(Product $root): int { return $root->id; }

    #[Field]
    public function name(Product $root): string { return $root->name; }

    #[Field]
    public function price(Product $root): float { return $root->price; }

    #[Field(description: 'Active in store?')]
    public function active(Product $root): bool { return $root->active; }

    #[Field(description: 'ISO 8601')]
    public function createdAt(Product $root): string {
        return $root->createdAt->format('c');
    }
}

// 2. Query resolver using the repository from DI
#[Query(name: 'product', description: 'Find product by ID')]
final class GetProductQuery
{
    public function __construct(private ProductRepository $products) {}

    public function __invoke(
        mixed $root,
        #[Arg(description: 'Product ID')] int $id,
        GraphQLContext $context,
    ): ?Product {
        return $this->products->find($id);
    }
}

// 3. List with filtering
#[Query(name: 'products', description: 'List products')]
final class ListProductsQuery
{
    public function __construct(private ProductRepository $products) {}

    public function __invoke(
        mixed $root,
        #[Arg(nullable: true)] ?bool $active,
        #[Arg(nullable: true, defaultValue: 20)] int $limit,
    ): array {
        if ($active !== null) {
            return $this->products->findByActive($active, $limit);
        }
        return $this->products->findAll($limit);
    }
}

// This happens automatically — no manual setup needed.
// The provider:
//   1. Reads config/graphql.mlc
//   2. Registers all GraphQL services in the DI container
//   3. Registers routes with MonkeysLegion\Router\Router

// Routes are registered as closures that delegate to PSR-15 middleware:
$router->post('/graphql', $graphqlHandler, 'graphql');
$router->get('/graphql', $graphqlHandler, 'graphql.get');
$router->get('/graphiql', $graphiqlHandler, 'graphiql'); // if enabled

use MonkeysLegion\GraphQL\Attribute\Middleware;

// Per-resolver middleware
#[Middleware('App\Middleware\AuthMiddleware')]
#[Middleware('App\Middleware\RateLimitMiddleware')]
#[Query(name: 'adminUsers')]
final class AdminUsersQuery
{
    public function __invoke(mixed $root, GraphQLContext $context): array
    {
        // Only reached if auth + rate-limit pass
        return $context->container->get(UserRepository::class)->findAdmins();
    }
}

use MonkeysLegion\GraphQL\GraphQL;

// Execute a query programmatically
$result = GraphQL::execute('{ user(id: 1) { name } }');

// Publish a subscription event
GraphQL::publish('messageAdded', $message);

// Get the built schema
$schema = GraphQL::schema();